출처: https://bumcrush.tistory.com/182 [맑음때때로 여름]

sqlite.org/download.html

 

SQLite Download Page

Templates (1) and (2) are used for source-code products. Template (1) is used for generic source-code products and templates (2) is used for source-code products that are generally only useful on unix-like platforms. Template (3) is used for precompiled bi

sqlite.org

 

 

내가 쓸 곳에 복사!

 

 

나가는건 .exit

 

import sys
import io

sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')


# 설치 안해도 그냥 내장되어있었음 pip list해도안나오지만..
import sqlite3

# db연결
con = sqlite3.connect('sample')

# 커서생성
cur = con.cursor()

# sql
sql_select = 'Select * from userTable'

cur.execute(sql_select)
print('아이디\t이름\t이메일\t생년')
print('-----------------------------------')

while True:
    # 커서의 한줄을 가져오는 함수 fetchone : 행이 없으면 NONE 반환
    row = cur.fetchone()

    if row :
        break;

    print(row)
    print('{}\t{}\t{}\t{}'.format(row[0], row[1], row[2], row[3]))

con.close()

 

 

'DB > M' 카테고리의 다른 글

[ORACLE SQL] 계정생성 in cmd  (0) 2020.11.16
[ORACLE SQL] 시퀀스 1로 초기화  (0) 2020.11.16
[ORACLE SQL] 단축키  (0) 2020.11.12
[ORACLE SQL] 기본 & 함수 문제 풀기  (0) 2020.11.10
[ORACLE SQL] 업체코드6552 에러  (0) 2020.11.10
from flask import Flask


# 웹서버 생성
app = Flask(__name__)
print(app)
print(__name__) #main

# url mapping
@app.route('/')
def index():
    return 'Hello, Python'

@app.route('/hello')
def hello():
    return '<h1> /hello 요청의 응답입니다 </h1>'


if __name__ == '__main__':
    app.run(debug=True, port=8000)

 

 

파이썬이 설치된 위치의 Script에 들어가서 cmd를 실행해준다.

그리고 pip install beatufulsoup4라고 치고 이렇게 나오면 설치완료!

 

 

아톰 사용하고 있고 그 뒤로는 이렇게 불러오기 가능!

쥬피터 노트북에는 깔려있고? VS CODE도 그냥 이렇게 쓰는 것 같다능~

근데 vscode는 터미널이 있어서 거기에서 하는듯..

 

설치 목록확인은 pip list

 

pip install flask

	String base64 = null;

		// 절대경로
		String realPath = ootdBase64Controller.class.getResource("/").getPath().replaceAll("/WEB-INF/classes/", "/");
		// 사진파일 이름
		String filePath = realPath + "fileupload/ootdimage/" + ootdphotoname;
		File imagefile = new File(filePath);

			FileInputStream input = new FileInputStream(imagefile);
			System.out.println(input);
			// 이미지 파일을 byte[] 로 읽어온다.
			byte[] b = new byte[input.available()];
			input.read(b);

			byte[] encoded = Base64.encodeBase64(b);
			// byte[] 형태의 base64 데이터를 String으로 변환.
			base64 = new String(encoded);
			System.out.println(base64);
			

 

apache common codec 사용

'memo' 카테고리의 다른 글

[자바] REST API 요청 시 한글깨짐  (0) 2021.02.17
[파이썬] pip 업그레이드  (0) 2021.02.17
[파이썬] 판다스 pandas 설치  (0) 2021.02.15
최근 에러 참고  (0) 2021.02.03
[스프링] ajax 참고  (0) 2021.01.29
RESTCLIENT  (0) 2021.01.28
[스프링] mvc패턴에 관한 블로그  (0) 2021.01.08

 

- AWS RDS 다른 컴퓨터에서 안될때 보안에서 IP 

m.blog.naver.com/PostView.nhn?blogId=baekmg1988&logNo=221316318423&proxyReferer=https:%2F%2Fwww.google.com%2F

 

[AWS] RDS DB 외부에서 접속 안될때 외부 접속 되게 하는 해결 방법

aws 클라우딩 서버 많이들 이용하시죠??ㅎㅎ 저도 친구들이랑 간단한 프로젝트 할 때는 아마존의 프리티어...

blog.naver.com

 

- append 했을때 onclick 등 쿼리안먹힐때

sup2is.tistory.com/90

 

[jQuery] jQuery append 이후 event 먹통 현상 대처

최대한 간략하게 설명해보면 다음과 같은 케이스가 있다 //html //javascript $('#somethingBtn').click(function () { $("#base").append(" bla bla "); }) $('.new').click(function() { //not working!!!!! });..

sup2is.tistory.com

 

- 모달로data넘기기

tristan91.tistory.com/415

 

bootstrap - modal로 데이터 넘기기

button을 누르면 delteCheckModal이 동작합니다. 게시글 삭제 deletecheckmodal 정말로 삭제하시겠습니까? aria-hidden="true">× '삭제'버튼을 누르면 해당 게시글이 삭제됩니다. 정말로 삭제하시겠습니까?..

tristan91.tistory.com

 

'memo' 카테고리의 다른 글

[파이썬] pip 업그레이드  (0) 2021.02.17
[파이썬] 판다스 pandas 설치  (0) 2021.02.15
자바스크립트 파일 절대경로 / decode  (0) 2021.02.08
[스프링] ajax 참고  (0) 2021.01.29
RESTCLIENT  (0) 2021.01.28
[스프링] mvc패턴에 관한 블로그  (0) 2021.01.08
tomcat서버 에러 발생시 해결 방법  (0) 2020.12.28
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <!-- <link rel="icon" href="../../../../favicon.ico"> -->

    <title>Offcanvas template for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="css/bootstrap/offcanvas.css" rel="stylesheet">
  </head>

  <body class="bg-light">

    <nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark">
      <a class="navbar-brand mr-auto mr-lg-0" href="#">BITCAMP</a>
      <button class="navbar-toggler p-0 border-0" type="button" data-toggle="offcanvas">
        <span class="navbar-toggler-icon"></span>
      </button>

      <div class="navbar-collapse offcanvas-collapse" id="navbarsExampleDefault">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item active">
            <a class="nav-link" href="#">Dashboard <span class="sr-only">(current)</span></a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Notifications</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Profile</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Switch account</a>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="https://example.com" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Settings</a>
            <div class="dropdown-menu" aria-labelledby="dropdown01">
              <a class="dropdown-item" href="#">Action</a>
              <a class="dropdown-item" href="#">Another action</a>
              <a class="dropdown-item" href="#">Something else here</a>
            </div>
          </li>
        </ul>
        <form class="form-inline my-2 my-lg-0">
          <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
          <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
        </form>
      </div>
    </nav>

    <div class="nav-scroller bg-white box-shadow">
      <nav class="nav nav-underline">
        <a class="nav-link active" href="#">Dashboard</a>
        <a class="nav-link" href="#">
          Friends
          <span class="badge badge-pill bg-light align-text-bottom">27</span>
        </a>
        <a class="nav-link" href="#">Explore</a>
        <a class="nav-link" href="#">Suggestions</a>
        <a class="nav-link" href="#">Link</a>
        <a class="nav-link" href="#">Link</a>
        <a class="nav-link" href="#">Link</a>
        <a class="nav-link" href="#">Link</a>
        <a class="nav-link" href="#">Link</a>
      </nav>
    </div>

    <main role="main" class="container">
      <div class="d-flex align-items-center p-3 my-3 text-white-50 bg-purple rounded box-shadow">
        
        <div class="lh-100">
          <h1 class="mb-0 text-white lh-100">MemberList</h1>
          <small>member info</small>
        </div>
      </div>

      <div class="my-3 p-3 bg-white rounded box-shadow" id="member_list">
        <h6 class="border-bottom border-gray pb-2 mb-0">Member List</h6>
        


        

      </div>

     
    </main>

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script>window.jQuery || document.write('<script src="js/assets/vendor/jquery-slim.min.js"><\/script>')</script>
    <script src="js/assets/vendor/popper.min.js"></script>
    <script src="js/bootstrap/bootstrap.min.js"></script>
    <script src="js/assets/js/vendor/holder.min.js"></script>
    <script src="js/bootstrap/offcanvas.js"></script>
    
    
    
    <script>
    
    	$(document).ready(function(){
    		
    		$.ajax({
    			url : 'http://localhost:8080/op/rest/ver1/members',
    			type : 'GET',
    			success : function(data){
    				console.log(data);
    				//alert(data);
    				//alert(JSON.stringify(data));
    				
    				
    				$.each(data, function(index, item){
    					
        				var html ='<div class="media text-muted pt-3">';
        				html += '<p class="media-body pb-3 mb-0 small lh-125 border-bottom border-gray">';
        				html += '<strong class="d-block text-gray-dark">'+item.memberid+'('+item.membername+')'+'</strong>';
        				html += ''+item.memberphoto;
        		    html += '</p>';
        		    html += '</div>';
        		    
        		    $('#member_list').append(html);
    				});
    				
    			},
    			error : function(e){
    				console.log("에러발생 : ",e);
    			}
    		})
 
    		
    	});
        
    </script>
    
    
    
    
    
    
  </body>
</html>

 

1 lib 세팅

 

pom.xml

websocket과 잭슨바인드 json을 자바의 객체로 쉽게 변경할 수 있는 gson을 넣어준다.

 

2 채팅을 위한 핸들러 클래스 정의

TextWebSocketHandler 상속해서 정의 - 접속 / 퇴장 / 메세지 전송

ace - 접속, htm - 메세지 전송, close -로그아웃 , List/Map = 저장공간

package com.aia.socket.handler;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.aia.socket.domain.Message;
import com.google.gson.Gson;

public class EchoHandler extends TextWebSocketHandler {

	private static final Logger logger = LoggerFactory.getLogger(EchoHandler.class);

	private List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>();
	private Map<String, WebSocketSession> sessionMap = new HashMap<String, WebSocketSession>();

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		
		String chatMember = (String) session.getAttributes().get("user");

		System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>" + chatMember);
		
		
		// 저장! 둘중에 하나 사용하면 되는데, 선생님은 둘다 넣어두심
		sessionList.add(session);
		// sessionMap.put(chatMember, session);

		logger.info("{} 연결되었습니다.", session.getId()+":"+chatMember);

		System.out.println("체팅 참여자 : " + chatMember);
	}

	@Override	//메세지보내기 			//누가보냈는지에 대한 정보저장↓
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

		// 현재 로그인된 멤버
		String chatMember = (String) session.getAttributes().get("user");
		
		logger.info("{}로 부터 {}를 전달 받았습니다.", chatMember, message.getPayload());
		
		
		Gson gson = new Gson();
							//json으로부터 객체를 만듦		//이 message클래스를 기반으로 json이만들어진다.
		Message msg = gson.fromJson(message.getPayload(), Message.class); 
		// ↑ json을 java의 객체로 바꿔주는 것.		// user, to, articleId, articleOwnver(방장?), message;
		
		System.out.println(msg);
		

		// 전달 메시지
		TextMessage sendMsg = new TextMessage(gson.toJson(msg));
		
					// sessionList 모두에게, afterConnectionEstablished에서 들어오는 인간들 저장했었음
		for (WebSocketSession webSocketSession : sessionList) {
			// 상대방에게 메시지 전달
			webSocketSession.sendMessage(sendMsg);
		}
		// 자신에게 메시지 전달
		//session.sendMessage(sendMsg); 
		
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		
		// 현재 유저 - 로그아웃
		String chatMember = (String) session.getAttributes().get("user");
		sessionList.remove(session);
		logger.info("{} 연결이 끊김", session.getId()+chatMember);
		System.out.println("체팅 퇴장 : " + chatMember);
	}

}
package com.aia.socket.domain;

public class Message {

	private String user;
	private String to;
	private String articleId;
	private String articleOwner;
	private String message;

	public Message(String user, String to, String articleId, String articleOwner, String message) {
		this.user = user;
		this.to = to;
		this.articleId = articleId;
		this.articleOwner = articleOwner;
		this.message = message;
	}

	public Message() {
	}

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}

	public String getTo() {
		return to;
	}

	public void setTo(String to) {
		this.to = to;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public String getArticleId() {
		return articleId;
	}

	public void setArticleId(String articleId) {
		this.articleId = articleId;
	}

	public String getArticleOwner() {
		return articleOwner;
	}

	public void setArticleOwner(String articleOwner) {
		this.articleOwner = articleOwner;
	}

	@Override
	public String toString() {
		return "Message [user=" + user + ", to=" + to + ", articleId=" + articleId + ", articleOwner=" + articleOwner
				+ ", message=" + message + "]";
	}



}

 

3. Spring-socket.xml 설정 파일 정의

 

설정파일 : 웹소켓 핸들러 bean 등록 

// handshake-interceptors = httpsession을 웹소켓세션으로 쓸 수 있게 해준다(?)

 

 

설정파일 : web.xml에 등록해주기!

 

 

4.

 

package com.aia.socket.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class ChattingController {

	@RequestMapping("/chatting")
	public ModelAndView chat(
			ModelAndView mv,
			@RequestParam("uid") String uid,
			HttpSession session
			) {
		
		mv.setViewName("chat/chat");
		mv.addObject("user", uid);
		mv.addObject("articleId", "12345");
		mv.addObject("articleOwner", "jin");
		
		session.setAttribute("user", uid);
		
		return mv;
	}
	
}
<%@ 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>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style>
	.text_right {
		text-align: right;
	}
	
	.text_left {
		text-align: left;
	}
	.chattingBox {
		padding : 15px;
		border : 1px solid #AAA;
		margin: 10px 0;
	}
</style>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>

<!-- 웹소켓 객체를 가져올 수 있게해준다 -->
<script
	src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>

<!-- Zebra-Dialog CDN -->
<!-- <script src="resources/js/dialog/zebra_dialog.src.js"></script>
<link rel="stylesheet" href="resources/css/dialog/zebra_dialog.css" type="text/css" /> -->

</head>
<body>

	<h1>Chatting Page (id: ${user})</h1>
	<br>
	<form>
		<div>
			<div>
				<input type="text" id="message" />
				<input type="submit" id="sendBtn" value="전송" />
			</div>
			<br>
			<div class="well" id="chatdata">
				<!-- User Session Info Hidden -->
				<input type="hidden" value='${user}' id="sessionuserid">
			</div>
		</div>
	</form>
</body>

<script>
	//websocket을 지정한 URL로 연결
	var sock = new SockJS("<c:url value="/echo"/>");
	//websocket 서버에서 메시지를 보내면 자동으로 실행된다.
	sock.onmessage = onMessage;
	//websocket 과 연결을 끊고 싶을때 실행하는 메소드
	sock.onclose = onClose;
	
	
	$(document).ready(function(){
		
		$("form").submit(function() {
			console.log('send message...');
			sendMessage();
			
			$('#message').val('');
			
			$('#message').focus();
			
			
			return false;
		});
		
	});
	
	$(function() {
	});

	function sendMessage() {
		//websocket으로 메시지를 보내기
		
		var msg = {
			user : '${user}',
			to : 'jin', // 현재 페이지 작성자의 id를 작성 (강제로하나써놈예제로)
			articleId : '${articleId}',
			articleOwner : '${articleOwner}',
			message : $("#message").val()
		};
		
		sock.send(JSON.stringify(msg));
	}

	//evt 파라미터는 websocket이 보내준 데이터다.
	function onMessage(evt) { //변수 안에 function자체를 넣음.
		var data = evt.data; // 전달 받은 데이터
		
		//alert(data);
		
		msgData = JSON.parse(data); 
		
		var sessionid = null;
		var message = null;
		
		//current session id//
		var currentuser_session = $('#sessionuserid').val();
		console.log('current session id: ' + currentuser_session);
		
		var target = $('#chattingBox-1');
		
		if(target.length==0){
			$('<div id=\"chattingBox-1\" class=\"chattingBox\"></div>').html('<h3>${user} : 게시물 작성자-'+msgData.articleOwner+'</h3>').appendTo('body');
			$('#chattingBox-1').append('<hr>')
		}

			

		// 나와 상대방이 보낸 메세지를 구분하여 출력
		if (msgData.user == currentuser_session) {
			var printHTML = "<div class='well text_right'>";
			printHTML += "<div class='alert alert-info'>";
			printHTML += "<strong>[" + msgData.user + "] -> " + msgData.message
					+ "</strong>";
			printHTML += "</div>";
			printHTML += "</div>";

			$('#chattingBox-1').append(printHTML);
		} else {
			var printHTML = "<div class='well text_left'>";
			printHTML += "<div class='alert alert-warning'>";
			printHTML += "<strong>[" + msgData.user + "] -> " + msgData.message
					+ "</strong>";
			printHTML += "</div>";
			printHTML += "</div>";

			$('#chattingBox-1').append(printHTML);
		}

		console.log('chatting data: ' + data);

		/* sock.close(); */
	}

	function onClose(evt) {
		$("#data").append("연결 끊김");
	}
</script>
</html>

chrome.google.com/webstore/detail/tabbed-postman-rest-clien/coohjcphdfgbiolnekdpbcijmhambjff

 

Tabbed Postman - REST Client

No separate window required! This is the legacy postman extension that can run in a Chrome tab. * Now runs in tab. * Does not…

chrome.google.com

http://localhost:8080/firstspring/members/26

GET방식으로 멤버 26번을 조회할때 결과물을 알 수 있다.

 

http://localhost:8080/firstspring/rest/ver1/members/map

map방식으로 나오는 결과물 볼 수 있다.

'memo' 카테고리의 다른 글

자바스크립트 파일 절대경로 / decode  (0) 2021.02.08
최근 에러 참고  (0) 2021.02.03
[스프링] ajax 참고  (0) 2021.01.29
[스프링] mvc패턴에 관한 블로그  (0) 2021.01.08
tomcat서버 에러 발생시 해결 방법  (0) 2020.12.28
Server Tomcat v8.5 Server at localhost failed to start  (0) 2020.12.23
과제  (0) 2020.11.14

1-1. pom.xml에 라이브러리 추가

<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>


<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

1-2. 서블릿 리퀘스트에 빈즈 추가

	<beans:bean id="mainSender"
	class="org.springframework.mail.javamail.JavaMailSenderImpl"
	>
	
	<beans:property name="host" value="smtp.gmail.com"/>
	<beans:property name="port" value="587"/>
	<beans:property name="username" value="hyoseonjinbit@gmail.com"/>
	<beans:property name="password" value="비밀번호라서지움ㅎㅎㅎㅎ"/>
	<beans:property name="defaultEncoding" value="UTF-8"/>
	<beans:property name="javaMailProperties">
		<beans:props>
			<beans:prop key="mail.transport.protocal">smtp</beans:prop>
			<beans:prop key="mail.transport.auth">true</beans:prop>
			<beans:prop key="mail.smtp.starttls.enable">true</beans:prop>
			<beans:prop key="mail.debug">true</beans:prop>
		</beans:props>
	</beans:property>	
	</beans:bean>
	
	
	<beans:bean id="templateEmailmessage"
	class="org.springframework.mail.SimpleMailMessage"
	p:subject="회원가입을 축하합니다"
	p:text="정상적인 가입을 위해 아래링크를 클릭해주세요"/>
package com.aia.firstspring.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.aia.firstspring.service.MailSenderService;

@Controller
@RequestMapping("/mail")
public class MailSenderController {
	
	@Autowired
	private MailSenderService mailService; 
	
	@RequestMapping("/simplemail")
	public void simpleMailSend() {
		
		mailService.simpleMailsend();
	}
	
	
	@Autowired
	private SimpleMailMessage templateMessage;
	
	@Autowired  
	private JavaMailSender mailsender;
	
	@RequestMapping("/simplemail2")
	public void simpleMailSend2() {
		
		mailService.mailSend("heeumheeum@naver.com");
		
		/*
		 * SimpleMailMessage message = new SimpleMailMessage(templateMessage);
		 * message.setTo("heeumheeum@naver.com");
		 * 
		 * mailsender.send(message);
		 */	
	}
	
}
package com.aia.firstspring.service;

import java.io.UnsupportedEncodingException;

import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;

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

@Service
public class MailSenderService {

	@Autowired  
	private JavaMailSender mailsender;
	
	public boolean simpleMailsend() {
		
		boolean result =true;

		
		SimpleMailMessage message = new SimpleMailMessage();
		message.setTo("hyein4coding@gmail.com");
		message.setSubject("인정합니까?");
		message.setText("인정합니다");
		try {
			mailsender.send(message);
		}catch (MailException e) {			
			result = false;
		}
		return result;
	}

	public boolean mailSend(String toEmailAddress) {
		
		boolean result = true;
		
		MimeMessage message = mailsender.createMimeMessage();
		try {
			
			// 메일의 제목 설정
			message.setSubject("[안내] 가입축하", "UTF-8"); 
			// 메일 내용
			String htmlStr = "<h1 style=\"color:red;\">가입축하드립니다 :)</h1>";
			message.setText(htmlStr, "UTF-8", "html");
			// 보내는 사람 이메일 : gmail을 사용하는 경우에는 인증된 메일처리가 된다.
			message.setFrom(new InternetAddress("hyoseonjinbit@gmail.com"));
			// 받는 사람의 이메일  주소
			message.addRecipient(RecipientType.TO, new InternetAddress("heeumheeum@naver.com","효선쓰","UTF-8"));
			// 메일 전송
			mailsender.send(message);
			
			
		} catch (MessagingException e) {
			result=false;
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			result=false;
			e.printStackTrace();
		}
		
		return result;
	}
	

	// 받는사람의메일주소, 받는이름, 메일제목, 메일내용
	public boolean mailSend(String toEmailAddress,String name, String subject, String text) {
		
		boolean result = true;
		
		MimeMessage message = mailsender.createMimeMessage();
		try {
			
			// 메일의 제목 설정
			message.setSubject(subject, "UTF-8"); 
			// 메일내용
			message.setText(text, "UTF-8", "html");
			// 보내는 사람 이메일 : gmail을 사용하는 경우에는 인증된 메일처리가 된다.
			message.setFrom(new InternetAddress("hyoseonjinbit@gmail.com"));
			// 받는 사람의 이메일  주소
			message.addRecipient(RecipientType.TO, new InternetAddress(toEmailAddress,name,"UTF-8"));
			// 메일 전송
			mailsender.send(message);
			
			
		} catch (MessagingException e) {
			result=false;
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			result=false;
			e.printStackTrace();
		}
		
		return result;
	}
}

 

 

package com.aia.firstspring.member.service;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.aia.firstspring.member.dao.MemberDao;
import com.aia.firstspring.member.dao.MemberInterfaceDao;
import com.aia.firstspring.member.dao.MybatisMemberDao;
import com.aia.firstspring.member.domain.Member;
import com.aia.firstspring.service.MailSenderService;

@Service
public class MemberRegService {

//	@Autowired
//	private MemberDao dao;
	
//	@Autowired
//	private MybatisMemberDao dao;
	
	private MemberInterfaceDao dao;
	
	@Autowired
	private SqlSessionTemplate template;
	
	@Autowired
	private MailSenderService mailService;
	
	
	public int insertMember(Member member) {
		int result = 0;
		try {
			dao = template.getMapper(MemberInterfaceDao.class);
			result = dao.insertMember(member);
			
			String htmlStr="<h1><a href=\"http://localhost:8080/op/firstspring\">인증하기</a></h1>";
			// 메일 전송
			mailService.mailSend(member.getMemberid(), member.getMembername(), "인증확인메일", htmlStr);
		} catch (Exception e) {
			e.printStackTrace();
		}
				
		return result;
	}
	
	
	
	
	
	
	
	
	
	
}
@@ -0,0 +1,14 @@
<%@ 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>
</body>
</html>

 

HTTP 통신 기반의 아키텍처 REST
-REST는 Representational State Transfer의 약어로 하나의 URI는 하나의 고유한 리소스를 대표하도록 설계된다는 개념.
- REST 방식은 특정한 URI는 반드시 그에 상응하는 데이터 자체라는 것을 의미. 예를 들면 /post/123은 해당 페이지의 번호의 123번이라는 고유한 의미를 가지고 설계하고, 이에 대한 처리는 GET, POST방식과 같이 추가적인 정보를 통해서 결정된다.
- REST API는 외부에서 위와 같은 방식으로 특정 URI를 통해서 사용자가 원하는 정보를 제공하는 방식.
- REST방식의 서비스 제공이 가능한 것을 Restful 하다고 표현.
- 스프링 3부터 @ResponseBody 애노테이션을 지원하면서 REST방식의 처리를 지원하고 있었으며, 스프링 4에 들어와서 @RestController가 본격적으로 적용.

 

REST API는 다음의 구성되어있다.
- 자원(RESOURCE) - URI
- 행위(Verb) - HTTP METHOD ( GET, POST, DELETE, PUT )
- 표현(Representations)

 

 

 

 

 

 

@PathVariable을 이용한 경로 변수 처리

- 경로의 특정 위치 값이 고정되지 않고 달라질 때 사용하는 것이 @PathVariable

 

 

 

 

 

 

 

@RequestBody & @ResponseBody

 

 

@RequestBody 과 @ResponseBody는 요청몸체와 응답 몸체 구현 
- @RequestBody  : JSON 형식의 요청 몸체를 자바 객체로 변환 
- @ResponseBody : 자바 객체를 JSON 이나 XML 형식의 문자열로 변환 
- Spring Framework는 HttpMessageConverter 를 이용해서 자바 객체와 HTTP 요청/응답 몸체 사이의 변환 처리

 

package com.aia.firstspring.controller;

import org.springframework.stereotype.Controller;
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;

@Controller
@RequestMapping("/mc/simple")
public class SimpleConvertercontroller {
	
	
	@RequestMapping(method = RequestMethod.GET)
	public String form() {
		
		return "simple/form";
	}
	
	@RequestMapping(method = RequestMethod.POST)
	@ResponseBody
	public String simple(@RequestBody String body) {
		
		System.out.println(body + " @ResponseBody 어노태이션은 일반객체도응답처리가된다 ");
		return body;
	}
		

}
<%@ 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>form</h1>
	
	<form method="post">
	name : <input type="text" name="uname"><br>
	age : <input type="number" name="age"><br>
	<input type="submit">
	</form>

</body>
</html>

 

 

 

 

JAXB2를 이용한 XML 처리

 

 

package com.aia.firstspring.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.aia.firstspring.domain.GuestMessage;
import com.aia.firstspring.domain.GuestMessageList;

@Controller
public class GuestMessageController {
	
	@RequestMapping("/message/listXml") 
	@ResponseBody
	public GuestMessageList listXml() {
		return getMessageList();
	}

	private GuestMessageList getMessageList() {

		List<GuestMessage> list = new ArrayList<GuestMessage>();
		list.add(new GuestMessage(1, "안녕", new Date()));
		list.add(new GuestMessage(2, "HELLO", new Date()));
		list.add(new GuestMessage(3, "빠이", new Date()));
		return new GuestMessageList(list);
	}
	

}
package com.aia.firstspring.domain;

import java.util.Date;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="", propOrder = {"id", "message", "regDate"})
public class GuestMessage {


	private int id;
	private String message;
	private Date regDate;
	
	
	public GuestMessage() {
	}

	public GuestMessage(int id, String message, Date regDate) {
		this.id = id;
		this.message = message;
		this.regDate = regDate;
	}
	
	
}
package com.aia.firstspring.domain;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="message-list") // <message-list></message-list>
public class GuestMessageList {
	
	
	@XmlElement(name="message")
	private List<GuestMessage> message;

	public GuestMessageList(List<GuestMessage> message) {
		this.message = message;
	}

	public List<GuestMessage> getMessage() {
		return message;
	}

	public void setMessage(List<GuestMessage> message) {
		this.message = message;
	}

	public GuestMessageList() {
	}
	
	
	

}

 

 

 

 

 

JACKSON2를 이용한 JSON 형식의 처리

 

 

잭슨 버전과 스프링 버전에 신경써서 해야함

 

 

 

package com.aia.firstspring.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.aia.firstspring.domain.GuestMessage;
import com.aia.firstspring.domain.GuestMessage2;
import com.aia.firstspring.domain.GuestMessageList2;

@Controller
public class GuestMessageController2 {
	

	@RequestMapping(value= "/message/listJson") 
	@ResponseBody
	public GuestMessageList2 listXml2() {
		return getMessageList2();
	}

	
	private GuestMessageList2 getMessageList2() {

		List<GuestMessage2> list2 = new ArrayList<GuestMessage2>();
		list2.add(new GuestMessage2(1, "안녕", new Date()));
		list2.add(new GuestMessage2(2, "HELLO", new Date()));
		list2.add(new GuestMessage2(3, "빠이", new Date()));
		return new GuestMessageList2(list2);
	}
	

}
package com.aia.firstspring.domain;

import java.util.Date;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

public class GuestMessage2 {
	
	private int id;
	private String message;
	private Date regDate;

	public GuestMessage2() {
	}

	public GuestMessage2(int id, String message, Date regDate) {
		this.id = id;
		this.message = message;
		this.regDate = regDate;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Date getRegDate() {
		return regDate;
	}

	public void setRegDate(Date regDate) {
		this.regDate = regDate;
	}
}
	
	
package com.aia.firstspring.domain;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;


public class GuestMessageList2 {

	private List<GuestMessage2> message;

	public GuestMessageList2(List<GuestMessage2> message) {
		this.message = message;
	}

	public List<GuestMessage2> getMessage2() {
		return message;
	}

	public void setMessage2(List<GuestMessage2> message) {
		this.message = message;
	}

	public GuestMessageList2() {
	}
	
	
	

}

'spring' 카테고리의 다른 글

[스프링부트] vs code 사용하기 메모  (0) 2021.03.08
[스프링] 웹소켓 : 채팅  (0) 2021.01.29
[스프링] 메일발송하기  (0) 2021.01.25
[스프링] 인터셉터 / intercepter  (0) 2021.01.15
[스프링] mapper / CRUD  (0) 2021.01.15
[스프링] mybatis  (0) 2021.01.12
[스프링] jdbc  (0) 2021.01.11

- preHandle()

컨트롤러가 호출되기 전에 실행된다. handler 파라메터는 핸들러 매핑이 찾아 준 컨트롤러 빈 오브젝트다. 컨트롤러 실행 이전에 처리해야 할 작업이 있다거나, 요청정보를 가공하거나 추가하는 경우에 사용할 수 있다. 또는 요청에 요청에 대한 로그를 남기기 위해 사용하기도 한다. 리턴 값이 true 이면 핸들러 실행 체인의 다음 단계로 진행되지만, false 라면 작업을 중단하고 리턴 하므로 컨트롤러와 남은 인터셉터들은 실행되지 않는다.
– postHandle() 

컨트롤러를 실행하고 난 후에 호출된다. 이 메소드에는 컨트롤러가 돌려준 ModelAndView 타입의 정보가 제공 되서 컨트롤러 작업 결과를 참조하거나 조작할 수 있다.
–afterCompletion() 

이름 그대로 모든 뷰에서 최종 결과를 생성하는 일을 포함한 모든 작업이 모두 완료된 후에 실행된다. 요청처리 중에 사용한 리소스를 반환해주기에 적당한 메소드다.

 

핸들러 인터셉터는 하나 이상을 등록할 수 있다. preHandle() 은 인터셉터가 등록된 순서대로 실행된다. 반면에 postHandle() 과 afterCompletion() 은 preHandle() 이 실행된 순서와 반대로 실행된다.

 

 

 

HandlerInterceptor를 통한 요청 가로채기

 

 

HandlerInterceptor 인터페이스의 구현
– 핸들러 인터셉터는 HandlerInterceptor 인터페이스를 구현해서 만든다. 이 인터페이스를 구현 할 경우 사용하지 않는 메서드도 구현 해주어야 한다.
– 이러한 불편함을 줄여주기 위해 HandlerInterceptorAdaptor 클래스를 제공.
– HandlerInterceptor 인터페이스를 구현해야 하는 클래스는 HandlerInterceptorAdaptor 클래스를 상속 받은 뒤 필요한 메서드만 오버라이딩 하여 사용.

 

 

 

1. HandlerMapping에 HandlerInterceptor 설정 하기

 

 

HandlerInterceptor를 구현 한 뒤에는 <mvc:interceptors> 의 interceptors 프로퍼티를 사용해

HandlerInterceptorAdaptor 를 등록해 주면 된다.

xmlns:mvc가아니라 생략되어 있으므로 <interceptors>로 등록했다.

 

2. HandlerInterceptor 인터페이스의 구현

 

 

 

예외처리

 

 

 

 

@ExceptionHandler 어노테이션을 이용한 처리

 

– AnnotationMethodHandlerExceptionResolver 클래스는 @Controller 어노테이션이 적용된 클래스에서 @ExceptionHandler 어노테이션이 적용된 메서드를 이용해서 예외 처리한다. @ModelAttribute 에서 ExceptionHandler 에서 지정한 예외가 발생하면 @ExceptionHandler가 적용된 메서드를 이용해서 뷰를 지정.

 

 

mypage3에서 강제로 예외를 발생시켜보았다. 에러가 발생시 error/nullpoiner.jsp로 이동한다.

 

 

'spring' 카테고리의 다른 글

[스프링] 웹소켓 : 채팅  (0) 2021.01.29
[스프링] 메일발송하기  (0) 2021.01.25
[스프링] REST API / @RequestBody @ResponseBody , HttpMessageConverter  (0) 2021.01.20
[스프링] mapper / CRUD  (0) 2021.01.15
[스프링] mybatis  (0) 2021.01.12
[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper 
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.aia.op.member.dao.MemberDao">

	<!-- Member 타입의 resultMap : 로그인시 사용 -->
	<resultMap id="memberResult"
		type="com.aia.op.member.domain.Member">
		<id column="idx" property="idx" />
		<result column="memberid" property="memberid" />
		<result column="membername" property="membername" />
		<result column="password" property="password" />
		<result column="memberphoto" property="memberphoto" />
		<result column="regdate" property="regdate" />
	</resultMap>


 <!-- Member 타입인데 위랑 다르게 비밀번호 안받음 -->
 
	<resultMap id="memberListResult"
			 type="com.aia.op.member.domain.Member">
		<id column="idx" property="idx" />
		<result column="memberid" property="memberid" />
		<result column="membername" property="membername" />
		<result column="memberphoto" property="memberphoto" />
		<result column="regdate" property="regdate" />
	</resultMap>




	<!-- 회원가입 -->
	<insert id="insertMember"
		parameterType="com.aia.op.member.domain.Member">
		
		INSERT INTO member
		
		<if test="memberphoto == null">		
		(memberid, password, membername)
		VALUES 
		(#{memberid},#{password},#{membername})
		</if>
		
		<if test="memberphoto != null">
		(memberid, password, membername, memberphoto)
		VALUES 
		(#{memberid},#{password},#{membername},#{memberphoto})
		</if>
		
		
		
	</insert>
	
	
	
	

	<!-- 로그인 -->
	<select id="selectLogin" resultMap="memberResult">
		select * from member where memberid=#{param1} and password=#{param2}
	</select>


	<!-- 회원의 총 수 -->
	<select id="selectTotalCount" resultType="int">
		select count(*) from
		member
	</select>


<!-- 멤버 리스트 구하기 -->
	<select id="selectMemberList"
					parameterType="map"
					resultMap="memberListResult">

		select * from member 
		<where>
			<if test="searchParam != null">
				<if test="searchParam.searchType == 'id'">
					<include refid="searchId"/>
				</if>
				<if test="searchParam.searchType == 'name'">
					<include refid="searchName"/>
				</if>
				<if test="searchParam.searchType == 'both'">
					<include refid="searchId"/>
					<include refid="searchName"/>
				</if>
			</if>
		</where>
		
		
		limit #{index}, #{count}

	</select>
	
	
	
	<!-- 검색 시 검색 결과에 나오는 회원의 수 구하기 -->
	<select id="selectSearchMemberCount" 
	        parameterType="com.aia.op.member.domain.SearchParam"
	        resultType="int"
	        >
	        
		select count(*) from member
		
		<!-- where idx>0  -->
		
		<where>
			<if test="searchParam.searchType == 'id'">
				  <!-- memberid like	concat('%',#{keyword},'%') -->
				  <include refid="searchId"/>
			</if>
			
			<if test="searchParam.searchType == 'name'">
				 <!-- membername like	concat('%',#{keyword},'%') -->
				 <include refid="searchName"/>
			</if>
			
			<if test="searchParam.searchType == 'both'">
				 <!-- membername like	concat('%',#{keyword},'%') 				 
				 or 
				 memberid like	concat('%',#{keyword},'%') --> 
				 <include refid="searchId"/>
				 <include refid="searchName"/>
			</if>
		</where>
		
			
	</select>
	
	
<!-- 가져다가 쓸수 있는 반복적인 sql문 만들기 / 아이디찾기 이름으로찾기 -->
	<sql id="searchId">
		or memberid like	concat('%',#{searchParam.keyword},'%')
	</sql>
	
	<sql id="searchName">
	  or membername like	concat('%',#{searchParam.keyword},'%')
	</sql>
	
	
<!-- 삭제 -->
	<delete id="deleteMemberByIdx">
		delete from member where idx=#{idx}
	</delete>


<!-- IDX를 기반으로 멤버찾기 -->
	<select id="selectMemberByIdx"
	        resultMap="memberListResult">
																		<!-- no를 쓴이유는 #{idx}가 아니어도 된다는 것을 보여주기위해 -->
		select * from member where idx=#{no}
		
	</select>



	<!-- 수정하기 -->
	<update id="updateMember"
					parameterType="com.aia.op.member.domain.Member">
	
		update member 
		set membername=#{membername}, 
				password=#{password}, 
				memberphoto=#{memberphoto}
		where idx=#{idx}  
	
	</update>









</mapper>d

'spring' 카테고리의 다른 글

[스프링] 메일발송하기  (0) 2021.01.25
[스프링] REST API / @RequestBody @ResponseBody , HttpMessageConverter  (0) 2021.01.20
[스프링] 인터셉터 / intercepter  (0) 2021.01.15
[스프링] mybatis  (0) 2021.01.12
[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08

설정하기

 

pom.xml에 라이브러리 등록해주기.

스프링 트랜잭션은 별다른 이유가 없는한 스프링프레임워크 버전과 맞춰준다. (나는 3.1.1이었음)

 

sqlsessionfactory bean등록하기 (id=SqlSessionFactory와 SqlSessionTemplate부분)

경로 안에있는 모든 xml파일을 mapper로사용하겠다는뜻

 

아직 mapper가 없어서 warn이뜨지만 제대로 실행되는 것을 볼 수 있다.

 

 

 

SqlSessionTemplate을 이용한 DAO 구현

 

예제1)

 

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

Mapper 작성 (id=selectAll)

 

 

package com.aia.firstspring.member.dao;

import java.util.List;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.aia.firstspring.domain.Member;

@Repository
public class MybatisMemberDao {
	
	
	private String nameSpace = "com.aia.firstspring.mybatis.mapper.memberMapper";
	@Autowired
	private SqlSessionTemplate template;
	
	public List<Member> selectMemberList(){
		return template.selectList(nameSpace + ".selectAll");
	}

}

Dao 작성

이전 코드와 비교했을때 Mybatis를 이용하면 코드가 매우간결해지는 것을 볼 수 있다.

(물론 서비스에서 Dao를 바꿔줘야하는 것 잊지말자)

 

 

 

예제2)

mapper 작성

 

	public int insertMember(Member member) {
		return template.update(nameSpace+ ".insertMember", member);
	}

Dao

 

 

예제3) 외래키값 가져오기.

 

이렇게 keyproperty를 이용하면 idx값을 받아올 수 있다.

 

 

자동 매퍼 생성 기능을 이용한 DAO 구현

 

package com.aia.firstspring.member.dao;

import java.util.List;

import com.aia.firstspring.domain.Member;

public interface MemberInterfaceDao {

	
	//abstract public 생략	
	List<Member> selectMemberList();
	int insertMember(Member member);
	int totalCount();
}

인터페이스생성!

MyBatis는 인터페이스를 이용해서 런타임에 매퍼 객체를 생성하는 기능을 제공한다.

 

마찬가지로 서비스에서 Dao를 바꿔줘야하는 것 잊지말아야하고

template를 주입받아야 한다.

 

Mapper

mapper에서는 인터페이스 안에 있는 메서드와 이름을 같에 만들어 주는 것이 중요하다.

이름이 같아야 자동으로 인식되기 때문이다 :)

 

'spring' 카테고리의 다른 글

[스프링] REST API / @RequestBody @ResponseBody , HttpMessageConverter  (0) 2021.01.20
[스프링] 인터셉터 / intercepter  (0) 2021.01.15
[스프링] mapper / CRUD  (0) 2021.01.15
[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08
[스프링] MVC : 패턴  (0) 2021.01.08

mysql / hikariCP / springjdbc라이브러리를 pom.xml에 등록

 

스프링은 버전에 맞춰서 라이브러리를 추가해주는데,

스프링 버전이 바뀔때마다 자동으로 바뀌게 하려면 이런식으로 값을 넣어주면 된다.

 

 

데이터 베이스 / JdbcTemplate 클래스 빈 등록 / root-context.xml

package com.aia.firstspring.domain;

import java.sql.Timestamp;
import java.util.Date;

public class Member {
	
	private int idx;
	private String memberid;
	private String password;
	private String membername;
	private String memberphoto;
	private Timestamp regdate;
	public int getIdx() {
		return idx;
	}
	public void setIdx(int idx) {
		this.idx = idx;
	}
	public String getMemberid() {
		return memberid;
	}
	public void setMemberid(String memberid) {
		this.memberid = memberid;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getMembername() {
		return membername;
	}
	public void setMembername(String membername) {
		this.membername = membername;
	}
	public String getMemberphoto() {
		return memberphoto;
	}
	public void setMemberphoto(String memberphoto) {
		this.memberphoto = memberphoto;
	}
	public Timestamp getRegdate() {
		return regdate;
	}
	public void setRegdate(Timestamp regdate) {
		this.regdate = regdate;
	}
	
	
	public Date getToDate() { // ${member.toDate}
		return new Date(getRegdate().getTime());
		
	}
	
	
	
	
	@Override
	public String toString() {
		return "Member [idx=" + idx + ", memberid=" + memberid + ", password=" + password + ", membername=" + membername
				+ ", memberphoto=" + memberphoto + ", regdate=" + regdate + "]";
	}
	
	

}

 

 

 

예제1) 회원리스트출력

 

Memberdao [@Reporitory]로 Dao를 등록해준다 (bean등록안해도 간단하게 등록가능)

package com.aia.firstspring.member.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.aia.firstspring.domain.Member;


@Repository
public class MemberDao {
	
	
	@Autowired
	private JdbcTemplate template;

	
	// jdbctemplate template 인스턴스를 주입
	// 1. 생성자 주입방식
	// 2. 프로퍼티 주입 방식
	// 3. 자동주입
	
	// 생성자를 이용한 객체 주입
	/*
	 * public MemberDao(JdbcTemplate t) { template = t;
	 * System.out.println("MemberDao 인스턴스 생성");
	 * 
	 * }
	 */
	
	public List<Member> selectMemberList() {
		String sql="select*from member order by memberid";
		
			return template.query(sql, new RowMapper<Member>() {

				@Override
				public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
					Member member = new Member();
					member.setIdx(rs.getInt("idx"));
					member.setMemberid(rs.getString("memberid"));
					member.setMembername(rs.getString("membername"));
					member.setPassword(rs.getString("password"));
					member.setMemberphoto(rs.getString("memberphoto"));
					member.setRegdate(rs.getTimestamp("regdate"));
					return member;
				}
			}	
				
			);
	}
	
	public int selectTotalCount() {
		String sql = "select count(*) from member";
		return template.queryForObject(sql, Integer.class);
	}
}

 

 

MemberListController

package com.aia.firstspring.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.aia.firstspring.member.service.MemberListService;

@Controller
public class MemberListController {
	
	@Autowired
	private MemberListService listService;
	
	
	@RequestMapping("/member/list")
	public String getMemberList(Model model) {	
		
		model.addAttribute("members",listService.getMemberList());
		model.addAttribute("memberCnt", listService.getMemberTotalCount());
		
		return "member/list";		
	}

}

MemberListService

package com.aia.firstspring.member.service;

import java.util.List;

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

import com.aia.firstspring.domain.Member;
import com.aia.firstspring.member.dao.MemberDao;

@Service
public class MemberListService {
	
	@Autowired
	MemberDao dao;
	
	/*
	 * public MemberListService(MemberDao dao) { this.dao=dao; }
	 */
	
	// 회원목록 반환 메서드
	public List<Member> getMemberList(){		
		return dao.selectMemberList();
	}
	
	// 회원수 몇명인지 int로 반환해주는 메서드
	public int getMemberTotalCount() {		
		return dao.selectTotalCount();
	}

}

view > list.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>
<head>
<meta charset="UTF-8">
<title>Member List</title>
</head>
<body>

	<h1>회원리스트</h1>

	<hr>
	${members}
	
	<h3>총회원수 ${memberCnt}</h3>

	<table>
		<tr>
			<th>idx</th>
			<th>id</th>
			<th>password</th>
			<th>name</th>
			<th>사진</th>
			<th>가입일</th>
		</tr>
		
		<c:forEach items="${members}" var="member"> 
			<tr>
				<td>${member.idx}</td>
				<td>${member.memberid}</td>
				<td>${member.password}</td>
				<td>${member.membername}</td>
				<td>${member.memberphoto}</td>
				<td>${member.toDate}</td>
			</tr>
		</c:forEach>
		
	</table>

</body>
</html>

 

 

 

 

예제2 ) 회원가입하기

 

컨트롤러 > 회원가입 성공시 리스트출력으로

package com.aia.firstspring.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.aia.firstspring.domain.Member;
import com.aia.firstspring.member.service.MemberRegService;

@Controller
@RequestMapping("/member/reg")
public class MemberRegController {
	
	@Autowired
	private MemberRegService regService;

	@RequestMapping(method = RequestMethod.GET)
	public String getRegForm() {
		return "member/regForm";
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String memberReg(Member member, Model model) {
		
		int resultCnt = regService.insertMember(member);
		String view="member/reg";
		model.addAttribute("resultCnt", resultCnt);
		
		if(resultCnt==1) {
			view= "redirect:/member/list";
		}
		return view;
	}
}

서비스

package com.aia.firstspring.member.service;

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

import com.aia.firstspring.domain.Member;
import com.aia.firstspring.member.dao.MemberDao;

@Service
public class MemberRegService {

	@Autowired
	private MemberDao dao;

	public int insertMember(Member member) {
		int result=0;
		try {
			result = dao.insertMember(member);
		}catch (Exception e){
			e.printStackTrace();
			
		}
		return result;
		
	}
}

MemberDao에 회원가입 메서드 추가

	public int insertMember(Member member) {
		//그냥 세개만 하기로 했음 ㅎ..
		String sql="insert into member (memberid, membername, password) values (?,?,?)";
		return template.update(sql, member.getMemberid(), member.getMembername(), member.getPassword());
		
	}

 

 

RegForm / name속성 맞춰줄것

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입 폼</title>
</head>
<body>

<h1>회원 가입 폼</h1>
<form method="post">
아이디 <input type="text" name="memberid"><br>
비밀번호 <input type="password" name="password"><br>
이름 <input type="text" name="membername"><br>
<input type="submit">


</form>
</body>
</html>

reg / 가입 실패시 나오는 창

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입 폼</title>
</head>
<body>

<h1>회원 가입 실패</h1>
${resultCnt}


</form>
</body>
</html>

'spring' 카테고리의 다른 글

[스프링] 인터셉터 / intercepter  (0) 2021.01.15
[스프링] mapper / CRUD  (0) 2021.01.15
[스프링] mybatis  (0) 2021.01.12
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08
[스프링] MVC : 패턴  (0) 2021.01.08
[스프링] DI / xml 설정파일 / 어노테이션  (0) 2021.01.06

 

 

MultipartResolover 설정

 

Multipart 지원 기능을 사용하려면 MultipartResolver를 스프링 설정 파일에 등록해야 한다.

Multipart 형식으로 데이터가 전송된 경우 해당 데이터를 스프링 MVC에서 사용 가능 하도록 변환해준다.

Commons FileUpload API 라이브러리를 이용해서 Multipart를 처리해 준다.

CommonsMultipartResolver를 MultipartResolver로 사용하기 위해서는 “multipartResolver” 이름의 빈으로 등록

 

 

파일업로드의 방법

1.@Requestparam 애노테이션을 이용한 업로드 파일 접근

2. MultipartHttpServletRequest 이용한 업로드 파일 접근

3. 커맨드 객체를 통한 업로드 파일 접근

MultipartRequest 인터페이스가 제공하는 메소드

 

입력받는 uploadForm.jsp

<%@ 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>
<h3>@RequestParam 이용한 파일 업로드</h3>
<form action="upload1" method="POST" enctype="multipart/form-data">
 
	 <!-- /fisrtspring/upload/uploadForm > /fisrtspring/upload/upload -->
	 
	 학번 : <input type="text" name="sn"><br>
	 리포트 파일 : 	<input type="file" name="report"><br>
	 <input type="submit">
	
</form>

<hr>
<h3>MultipartHttpServletRequest를 이용한 파일 업로드</h3>
<form action="upload2" method="POST" enctype="multipart/form-data">
	 
	 학번 : <input type="text" name="sn"><br>
	 리포트 파일 : 	<input type="file" name="report"><br>
	 <input type="submit">
	
</form>



<hr>
<h3>커맨드 객체를 통한 업로드 파일 접근</h3>
<form action="upload3" method="POST" enctype="multipart/form-data">
	 
	 학번 : <input type="text" name="sn"><br>
	 리포트 파일 : 	<input type="file" name="report"><br>
	 <input type="submit">
	
</form>

</body>
</html>

컨트롤러 FileuploadController.java

package com.aia.firstspring.controller;

import java.io.File;
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.aia.firstspring.domain.ReportUploadRequest;

@Controller
public class FileuploadController {

	final String uri = "/uploadfile";

	@RequestMapping("/upload/uploadForm")
	public String uploadForm() {
		return "upload/uploadForm";
	}

	
	
	@RequestMapping("/upload/upload1")
	public String upload1(
			@RequestParam("sn") String sn,
			@RequestParam("report") MultipartFile report, 
			Model model,
			HttpServletRequest request) throws IllegalStateException, IOException {

		System.out.println(report.getOriginalFilename());

		model.addAttribute("sno", sn);
		model.addAttribute("reportFile", report.getOriginalFilename());
		
		// 파일의 저장
		report.transferTo(getFile(request, uri, report.getOriginalFilename()));

		return "upload/uploadComplete";
	}

	
	
	
	
	@RequestMapping("/upload/upload2")
	public String upload2(MultipartHttpServletRequest request, Model model) throws IllegalStateException, IOException {

		String sn = request.getParameter("sn");
		MultipartFile report = request.getFile("report");

		System.out.println(report.getOriginalFilename());

		model.addAttribute("sno", sn);
		model.addAttribute("reportFile", report.getOriginalFilename());
		
		// 파일 저장
		report.transferTo(getFile(request, uri, report.getOriginalFilename()));

		return "upload/uploadComplete";
	}
	
	
	

	@RequestMapping("/upload/upload3")
	public String upload3(
			ReportUploadRequest uploadrequest,
			Model model,
			HttpServletRequest request) throws IllegalStateException, IOException {

		System.out.println(uploadrequest.getReport().getOriginalFilename());

		model.addAttribute("sno", uploadrequest.getSn());
		model.addAttribute("reportFile", uploadrequest.getReport().getOriginalFilename());
		
		// getReport = 멀티파트파일
		uploadrequest.getReport().transferTo(getFile(request, uri,uploadrequest.getReport().getOriginalFilename())); 

		return "upload/uploadComplete";
	}


	
	
	
	/*
	  private String getRealpath(HttpServletRequest request, String uri) { return
	  request.getSession().getServletContext().getRealPath(uri); }
	 */

	
	// File 객체를 생성해서 반환
	private File getFile(HttpServletRequest request, String uri, String fileName) {
		String rpath = request.getSession().getServletContext().getRealPath(uri);
		File newFile = new File(rpath, fileName);
		return newFile;
	}
}

커맨드 객체를 이용하기 위한 ReportUploadRequest.java

package com.aia.firstspring.domain;

import org.springframework.web.multipart.MultipartFile;

public class ReportUploadRequest {
	
	private String sn;
	private MultipartFile report;
	
	public String getSn() {
		return sn;
	}
	public void setSn(String sn) {
		this.sn = sn;
	}
	public MultipartFile getReport() {
		return report;
	}
	public void setReport(MultipartFile report) {
		this.report = report;
	}

	
}

 

결과 view / uploadeComplete.jsp

<%@ 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> 학생 1 학번 : ${sno} , 리포트 파일 : ${reportFile}</h1>
<img alt="레포트이미지" src="../uploadfile/${reportFile}">

</body>
</html>

 

 

 

hunit.tistory.com/190

 

Spring〃Dispatcher Servlet / HandlerMapping 설정

MVC 패턴 흐름을 정리하면서 새로운 용어인 DispatcherServlet이라는게 새로 튀어나왔죠? 바로 저번글에서 한번에 정리할까 하다가 그냥 따로 하나의 주제로 정리하는게 낫다 싶어서 게시글을 분리했

hunit.tistory.com

 

hunit.tistory.com/189

 

Spring〃스프링 MVC 패턴의 흐름

스프링 프레임워크 기반으로 게시판을 짜기 위해 MVC(Model / View / Controller) 패턴을 사용할 예정이라 이번글에서 정리해보도록 하겠습니다. 스프링 MVC 패턴은 좀 복잡한 구조를 가지고 있지만, 며

hunit.tistory.com

 

 

'memo' 카테고리의 다른 글

최근 에러 참고  (0) 2021.02.03
[스프링] ajax 참고  (0) 2021.01.29
RESTCLIENT  (0) 2021.01.28
tomcat서버 에러 발생시 해결 방법  (0) 2020.12.28
Server Tomcat v8.5 Server at localhost failed to start  (0) 2020.12.23
과제  (0) 2020.11.14
이클립스(Eclipse) 개발환경 / uft-8  (0) 2020.11.02

컨트롤러 구현

 

 

@Controller 애노테이션 이용을 권장하며,

@Controller & @RequestMapping 는 구현을 위한 필수 애노테이션이다.

@Controller Controller 클래스 정의 
@RequestMapping HTTP요청 URL을 처리할 Controller 메소드 정의 
@RequestParam HTTP 요청에 포함된 파라미터 참조 시 사용 
@ModelAttribute HTTP 요청에 포함된 파라미터를 모델 객체로 바인딩

                                 @ModelAttribute의 ‘name’으로 정의한 모델 객체를 다음 View에게 사용 가능

 

 

 

문법

1. 요청 URL만 선언할 경우

@RequestMapping("/요청url")

2. 요청방식을 지정한 경우

@RequestMapping( value="/요청url" method=RequestMethod.메서드방식(ex)get/post)

 

Controller의 처리 결과를 보여줄 View 지정 방법 / 메소드의 반환 값에 따른 view page지정 방법

1. ModelAndView인 경우

setViewName() 메소드 파라미터로 설정

2. String인 경우

메소드의 리턴 값

 

 

 

예제

 

RequestMapping 예제 - 요청방식 지정에 따른 경우 

package com.aia.firstspring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.aia.firstspring.member.domain.LoginRequest;

@Controller
@RequestMapping("/member/login")
public class memberLoginController {
	//사용자의 요청 url 처리해야될 기능, 메서드를 바인딩 하는 것이 컨트롤러다.
	
	// @RequestMapping(value = "/member/login", method = RequestMethod.GET)
		@RequestMapping(method = RequestMethod.GET)
		public ModelAndView getLoginForm() {
			return new ModelAndView("member/loginForm"); // setViewName과 동일, 
		}
		
		// @RequestMapping(value = "/member/login", method = RequestMethod.POST)
		@RequestMapping(method = RequestMethod.POST)
		public ModelAndView login() {

			ModelAndView mav = new ModelAndView();
			mav.setViewName("/member/login"); // 로그인 되었을 때 보이는 페이지 -> mapping에 밸류가 동일해서 오류 생김
			return mav;
		}

	}

 

 

 

사용자의 파라미터값을 받는 방법
1. HttpServletRequest 객체 이용
2. @RequestParam(폼의 네임속성)
3. 커맨드 객체(Beans) 이용

 

 

 

@RequestParam 예제 = @RequestParam(폼의 네임속성) 

package com.aia.firstspring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.aia.firstspring.member.domain.LoginRequest;

@Controller
@RequestMapping("/member/login")
public class memberLoginController {
	//사용자의 요청 url 처리해야될 기능, 메서드를 바인딩 하는 것이 컨트롤러다.
	
	// @RequestMapping(value = "/member/login", method = RequestMethod.GET)
		@RequestMapping(method = RequestMethod.GET)
		public ModelAndView getLoginForm() {
			return new ModelAndView("member/loginForm"); // setViewName과 동일, 
		}
		
		// @RequestMapping(value = "/member/login", method = RequestMethod.POST)
		@RequestMapping(method = RequestMethod.POST)
		public ModelAndView login(
				@RequestParam("uid") String uid,
				@RequestParam("pw") String pw) {
			//리퀘스트파람이 파라미터를 받아올 수 있게 해준다.

			ModelAndView mav = new ModelAndView();
			mav.setViewName("/member/login"); // 로그인 되었을 때 보이는 페이지 -> mapping에 밸류가 동일해서 오류 생김
			mav.addObject("uid", uid);
			mav.addObject("pw", pw);
			
			return mav;
		}

	}

.

 

HttpServletRequest = HttpServletRequest 객체 이용 

 

package com.aia.firstspring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.aia.firstspring.member.domain.LoginRequest;

@Controller
@RequestMapping("/member/login")
public class memberLoginController {
	//사용자의 요청 url 처리해야될 기능, 메서드를 바인딩 하는 것이 컨트롤러다.
	
	// @RequestMapping(value = "/member/login", method = RequestMethod.GET)
		@RequestMapping(method = RequestMethod.GET)
		public ModelAndView getLoginForm() {
			return new ModelAndView("member/loginForm"); // setViewName과 동일, 
		}
		
		// @RequestMapping(value = "/member/login", method = RequestMethod.POST)
		@RequestMapping(method = RequestMethod.POST)
		public ModelAndView login(
				HttpServletRequest request) {

			
			String userId = request.getParameter("uid");
			String userPw = request.getParameter("pw");
			
			ModelAndView mav = new ModelAndView();
			mav.addObject("userId", userId);
			mav.addObject("userPw",userPw);
			
			return mav;
		}

	}

 

커맨드 객체 = (Beans) 이용 

이때 객체간의 파라미터 이름이 같아야 한다!!!!!!

package com.aia.firstspring.member.domain;

public class LoginRequest {

	
	// 변수의 이름이 form에있는 name과 같아야 한다.
	String uid;
	String pw;
	
	public String getUid() {
		return uid;
	}
	public void setUid(String uid) {
		this.uid = uid;
	}
	public String getPw() {
		return pw;
	}
	public void setPw(String pw) {
		this.pw = pw;
	}
	@Override
	public String toString() {
		return "LoginRequest [uid=" + uid + ", pw=" + pw + "]";
	}
	
	
}
package com.aia.firstspring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.aia.firstspring.member.domain.LoginRequest;

@Controller
@RequestMapping("/member/login")
public class memberLoginController {
	//사용자의 요청 url 처리해야될 기능, 메서드를 바인딩 하는 것이 컨트롤러다.
	
	// @RequestMapping(value = "/member/login", method = RequestMethod.GET)
		@RequestMapping(method = RequestMethod.GET)
		public ModelAndView getLoginForm() {
			return new ModelAndView("member/loginForm"); // setViewName과 동일, 
		}
		
		// @RequestMapping(value = "/member/login", method = RequestMethod.POST)
		@RequestMapping(method = RequestMethod.POST)
		public ModelAndView login(
				HttpServletRequest request,
				LoginRequest loginRequest) {
			
			// login("cool","1111")
			System.out.println(loginRequest);
			
			String userId = request.getParameter("uid");
			String userPw = request.getParameter("pw");
			
			ModelAndView mav = new ModelAndView();
			mav.addObject("userId", userId);
			mav.addObject("userPw", userPw);
			//mav.addObject("loginRequest", loginRequest); 
			//안해도 공유가 됨 변수이름은 클래스 이름의 앞글자를 소문자로 바꾼 것으로 됨
			
			return mav;
		}

	}

 

 

 

 

MVC : List 타입의 프로퍼티 바인딩 처리하기 예제

 

 

아이템 목록 : OrderItem.java

package com.aia.firstspring.domain;

public class OrderItem {
	
	private String itemId;
	private String number;
	private String remark;
	public String getItemId() {
		return itemId;
	}
	public void setItemId(String itemId) {
		this.itemId = itemId;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
	@Override
	public String toString() {
		return "OrderItem [itemId=" + itemId + ", number=" + number + ", remark=" + remark + "]";
	}
	
	

}

 

주소 목록 : Address.java

package com.aia.firstspring.domain;

public class Address {
	
	private String zipcode;
	private String address1;
	private String address2;
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
	public String getAddress1() {
		return address1;
	}
	public void setAddress1(String address1) {
		this.address1 = address1;
	}
	public String getAddress2() {
		return address2;
	}
	public void setAddress2(String address2) {
		this.address2 = address2;
	}
	
	@Override
	public String toString() {
		return "Address [zipcode=" + zipcode + ", address1=" + address1 + ", address2=" + address2 + "]";
	}
	
	

}

 

orderCommand.java

/ 커맨드는 이걸루 사용 

/ 주소랑 상품 묶어줌

package com.aia.firstspring.domain;

import java.util.List;

public class orderCommand {
	
	private List<OrderItem> orderItems; 
	private Address address;
	public List<OrderItem> getOrderItems() {
		return orderItems;
	}
	public void setOrderItems(List<OrderItem> orderItems) {
		this.orderItems = orderItems;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "orderCommand [orderItems=" + orderItems + ", address=" + address + "]";
	}
	
	

}

 

컨트롤러 OrderControoler.java

GET / POST 타입 방식에 따른 리퀘스트맵핑

@ModelAttribute 애노테이션을 사용하여 모델명을 설정 (uo로 줄여줌)

package com.aia.firstspring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.aia.firstspring.domain.orderCommand;

@Controller
@RequestMapping("/order/order")
public class OrderController {
	
	@RequestMapping(method = RequestMethod.GET)
	public String getOrderForm() {
	    	return "order/orderForm";
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String orderComplete(@ModelAttribute("uo") orderCommand order) {
		System.out.println(order);
		return "order/orderComplete";
	}

}

 

[VIEW-1]

입력받을 폼 > orderForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>주문</title>
</head>
<body>

	<h1>주문 폼</h1>
	<form method="post">
		<table border="1">
			<tr>
				<td rowspan="3">상품-1</td>
				<td>ID</td>
				<td><input type="text" name="orderItems[0].itemId"></td>
			</tr>
			<tr>
				<td>개수</td>
				<td><input type="number" name="orderItems[0].number"></td>
			</tr>
			<tr>
				<td>주의</td>
				<td><input type="text" name="orderItems[0].remark"></td>
			</tr>
			<tr>
				<td rowspan="3">상품-2</td>
				<td>ID</td>
				<td><input type="text" name="orderItems[1].itemId"></td>
			</tr>
			<tr>
				<td>개수</td>
				<td><input type="number" name="orderItems[1].number"></td>
			</tr>
			<tr>
				<td>주의</td>
				<td><input type="text" name="orderItems[1].remark"></td>
			</tr>
			<tr>
				<td rowspan="3">상품-3</td>
				<td>ID</td>
				<td><input type="text" name="orderItems[2].itemId"></td>
			</tr>
			<tr>
				<td>개수</td>
				<td><input type="number" name="orderItems[2].number"></td>
			</tr>
			<tr>
				<td>주의</td>
				<td><input type="text" name="orderItems[2].remark"></td>
			</tr>
			<tr>
				<td rowspan="3">주소</td>
				<td>우편번호</td>
				<td><input type="text" name="address.zipcode"></td>
			</tr>
			<tr>
				<td>주소1</td>
				<td><input type="text" name="address.address1"></td>
			</tr>
			<tr>
				<td>주소2</td>
				<td><input type="text" name="address.address2"></td>
			</tr>
			<tr>
				<td></td>
				<td><input type="submit"></td>
				<td></td>
			</tr>
		</table>

	</form>

</body>
</html>

[VIEW-2]

결과출력 > orderComplete.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>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h1>주문정보</h1>
	
	<h3>상품 주문 정보</h3>
	
	<c:forEach items="${uo.orderItems}" var="oi">
		<div>
			상품 ID : ${oi.itemId} / 개수 : ${oi.number}개 / 주의사항 : ${oi.remark} 	
		</div>	
	</c:forEach>
	
	<h3>배송지</h3>
	<div>
	
		우편번호 : ${uo.address.zipcode}
		주소1 :  ${uo.address.address1}
		주소2 :  ${uo.address.address2}
	</div>
	
</body>
</html>

 

1단계 – client의 요청을 받을 DispatcherServlet 을 web.xml 파일에 설정

 

ContextLoaderListener

- 디스패쳐서블릿의 부모(모든서블릿에 공통적용) / 디스패쳐서블릿 여러개 설정시 필수로 리스너 설정

 

DispatcherServlet / 서블릿매핑

- url패턴의 / 로 해줌. 보통 학원 예제에서는 .do로 많이 나온 부분

/ <- 로 요청되는 모든 client 의 요청을 DispatcherServlet이 처리하도록 요청

/ 이때 servlet-context.xml 이라는 이름의 Spring 설정 파일을 사용하도록 설정

 

2단계 – 컨트롤러 구현 및 설정 추가 하기 

 

컨트롤러 구현

@Controller – Spring MVC의 controller 를 구현한 클래스로 지정

@RequestMapping –/hello 라는 url값으로의 요청을 처리할 메소드 지정

 

설정파일에 등록 / 생략가능(여기선생략함)

servlet-context.xml 

 

package com.aia.firstspring.controller;

import java.util.Calendar;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;


//컨트롤 클래스라고 알려주는 어노테이션 > 이걸 해주어야 handler mapping에 등록
@Controller 
public class HelloController {
	
	// 이 메서드는 프론트컨트롤러 쪽으로 Viewname을 반환해야 한다.
	// 반환 타입은 ModelAndView를 이용해서 반환하자.
	@RequestMapping("/hello")
	public ModelAndView hello() {
		ModelAndView mav = new ModelAndView();
		
		// prefix suffix를 제외한 이름 /WEB-INF/views/member/hello.jsp -> member/hello
 		mav.setViewName("member/hello");
 		mav.addObject("greeting", greeting());
		
		return mav;
	}

	private String greeting() {
		String result = "안녕!";
		
		int nowTime = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
		if(nowTime>=6 && nowTime <= 10) {
			result="좋은 아침";
		} else if(nowTime >= 12 && nowTime<=15) {
			result="맛점";
		} else if(nowTime >=18 && nowTime<=22) {
			result="굿밤";
		}
		
		return result;
	}

}

 

 

3단계 – 설정파일에 viewResolver 설정 추가하기

이부분이 viewResolver

Context 설정 추가

/ namespace에서 context 추가 필수

/ 빈 설정

/ 기본패키지를 컨트롤러로 연결시켜줌

 

 

3.5단계 -  필요하다면 핸들러매핑(의존성주입)


4단계 – JSP를 이용한 View 영역의 코드 작성 


5단계 – 실행

 

우리가 보던 인터넷 사이트처럼 주소가 깔끔해짐 .jsp 이런거 없어졌다!

 

 

 

 

 

 

의존성 주입

 

 

Spring Framework가 지원하는 핵심 기능으로 객체 사이의 의존 관계가 객체 자신이 아닌 외부(조립기)에 의해 설정된다. 외부 조립기는 xml 설정 파일을 기반으로 의존을 설정한다.

 

package member.dao;

public interface Dao {
	
	// public abstract void insert();
	
	void insert();
	void select();
	void delete();
	void update();
}
package member.dao;

public class MemberDao implements Dao {

	@Override
	public void insert() {
		System.out.println("회원 정보 데이터베이스 저장");

	}

	@Override
	public void select() {
		System.out.println("회원 정보 검색");
	}

	@Override
	public void delete() {
		System.out.println("회원 정보 삭제");

	}

	@Override
	public void update() {
		System.out.println("회원 정보 수정");
	}

}

 

 

생성자 타입의 주입방식

 

package member.service;

import member.dao.Dao;

public class MemberRegService implements MemberService {

	// Dao dao = new MemberDao(); // 의존성이 높은 코드이므로 X
	
	
	/* 생성자 방식 */
	
	private Dao dao; // 주입받아야하는 참조변수
	
	// 생성자를 통해서 Dao타입의 인스턴스를 주입받는다.
	// Dao dao = new MemberDao(); -> 다형성.
	public MemberRegService(Dao dao) {
		this.dao = dao;
	}
	
	@Override
	public Object process() {
		System.out.println("MemberRegService 실행");
		dao.insert();
		
		return null;
	}
	
	

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- MemberDao를 Bean(인스턴스)으로 등록 -->
	<bean
	id="memberDao"
	class="member.dao.MemberDao"
	>
	</bean>
	
	<!-- MemberRegService bean으로등록 -->
	<bean id="memberRegService" 
		class="member.service.MemberRegService">
	<!-- <constructor-arg ref="memberDao"/> -->
	<constructor-arg>
		<ref bean="memberDao"/>
	</constructor-arg>
	</bean>
    
</beans>

 

 

프로퍼티 타입의 주입방식

 

package member.service;

import member.dao.Dao;

public class MemberInfoService implements MemberService{
	
	/* 프로퍼티 타입 */
	Dao dao;
	
	// 프로퍼티 타입의 주입 방식 : setter 메소드 정의가 필요하다
	public void setDao(Dao dao) {
		this.dao = dao;
	}
	
	
	
	
	@Override
	public Object process() {
		System.out.println("MeberInfoService 실행");
		dao.select();
		return null;
	}

}
 <!-- 멤버인포서비스 Bean등록 -->
 <bean id="memberInfoService" class="member.service.MemberInfoService">
 <!-- <property name="dao" ref="memberDao"></property> -->
 <property name="dao">
 		<ref bean="memberDao"/>
 </property>

 

MemberMain 실행

package member.main;

import org.springframework.context.support.GenericXmlApplicationContext;

import member.service.MemberInfoService;
import member.service.MemberRegService;

public class MemberMain {

	public static void main(String[] args) {

		
		//1. Spring 컨테이너 생성
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:appCtx.xml");
	
		//2. MemberRegService 객체가 필요
		MemberRegService regService = ctx.getBean("memberRegService", MemberRegService.class);

		//3. MemberRegService 프로세스 메서드 실행
		regService.process();
		
		//4. MemberinfoService 객체가 필요
		MemberInfoService infoService = ctx.getBean("memberInfoService", MemberInfoService.class);
		
		//5. MemberInfoService 프로세스 메서드 실행
		infoService.process();
	}

}

 

xml 설정파일

 

1. XML 네임스페이스를 이용한 프로퍼티 설정

 <!-- 멤버인포서비스 Bean등록 -->
 <bean id="memberInfoService" class="member.service.MemberInfoService">
 <!-- <property name="dao" ref="memberDao"></property> -->
 <property name="dao">
 		<ref bean="memberDao"/>
 </property>
 
 
 
 ↓ 아래처럼 간결해짐
 	<!-- 프로퍼티 방식에서 p를 사용하면 속성을 사용하지 않고 한 줄 처리가 가능 -->	
    

<!-- 멤버인포서비스 Bean등록 -->
 <bean id="memberInfoService" class="member.service.MemberInfoService"
 	p:dao-ref="memberDao">

 </bean>
</beans>

 

2. 의존관계 설정 : 임의 빈 객체 전달

 <bean id="memberInfoService" class="member.service.MemberInfoService">
 <!-- <property name="dao" ref="memberDao"></property> -->
 <property name="dao">
 		<bean class="member.dao.MemberDao"/>
 </property>
 

 

3. 여러개의 xml 사용 / 두 개 이상의 설정파일 사용하기 > import 이용

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<import resource="classpath:appCtx4_1.xml"/>
<import resource="classpath:appCtx4_2.xml"/>

</beans>

 

 

 

 

 

DI - 의존관계자동설정

 

 

 

 

빈 객체 범위

 

xml에서 scope 설정

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- MemberDao를 Bean(인스턴스)으로 등록 -->
	<bean
	id="memberDao"
	class="member.dao.MemberDao"
	>
	</bean>
	
	<!-- MemberRegService bean으로등록 -->
	<bean id="memberRegService" 
				class="member.service.MemberRegService"
				scope="prototype"
				>	
	<constructor-arg>
		<ref bean="memberDao"/>
	</constructor-arg>
	</bean>
	
 
 <!-- 멤버인포서비스 Bean등록 -->
 <bean id="memberInfoService"
 			class="member.service.MemberInfoService"
 			scope="singleton">
 <property name="dao">
 		<bean class="member.dao.MemberDao"/>
 </property>
 
 </bean>
</beans>
package member.main;

import org.springframework.context.support.GenericXmlApplicationContext;

import member.dao.Dao;
import member.service.MemberInfoService;
import member.service.MemberRegService;

public class MemberMain2 {

	public static void main(String[] args) {

		
		//1. Spring 컨테이너 생성
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:appCtx5.xml");
		
		

		Dao dao1 = ctx.getBean("memberDao", Dao.class);
		Dao dao2 = ctx.getBean("memberDao", Dao.class);
		
		// 아무 처리도 하지않으면 기본적으로 싱글톤이다.
		System.out.println("dao1참조변수 == dao2참조변수 ? " +(dao1==dao2));
		
		//2. MemberRegService 객체가 필요
		MemberRegService regService1 = ctx.getBean("memberRegService", MemberRegService.class);
		MemberRegService regService2 = ctx.getBean("memberRegService", MemberRegService.class);
		
		// 프로포타입이므로 false
		System.out.println("regService1==regService2 ? " + (regService1==regService2));
		
		
		//4. MemberinfoService 객체가 필요
		MemberInfoService infoService1= ctx.getBean("memberInfoService", MemberInfoService.class);
		MemberInfoService infoService2= ctx.getBean("memberInfoService", MemberInfoService.class);
		// 싱글톤타입이므로 true > 둘의참조변수가같다
		System.out.println("infoService1==infoService2 ? " + (infoService1==infoService2));
		
		
	}

}

 

.

 

 

 

애노테이션 기반 설정

JDK5 버전부터 추가된 것으로 메타데이터를 XML등의 문서에 설정하는 것이 아니라 소스 코드에 “@애노테이션”의 형태로 표현하며 클래스, 필드, 메소드의 선언부에 적용 할 수 있는 특정 기능이 부여된 표현법이다. 프레임워크들이 활성화 되고 애플리케이션 규모가 커질수록 XML 환경 설정은 복잡해지는데, 이러한 어려움을 개선시키기 위하여 자바 파일에 애노테이션을 적용해서 코드를 작성함으로써 개발자가 설정 파일에 작업하게 될 때 발생시키는 오류의 발생 빈도를 낮춰주기도 한다.

 

 

Java 에서 이미 정의되어 있는 애노테이션


@Override - 메소드가 오버라이드 됐는지 검증.

                 부모 클래스 또는 구현해야 할 인터페이스에서 해당 메소드를 찾을 수 없다면 컴파일 오류. 
@Deprecated - 메소드를 사용하지 말도록 유도. 만약 사용한다면 컴파일 경고. 
@SuppressWarnings - 컴파일 경고를 무시. 
@SafeVarargs - 제너릭 같은 가변인자 매개변수를 사용할 때 경고를 무시.(자바7 이상) 
@FunctionalInterface - 람다 함수등을 위한 인터페이스를 지정.

                               메소드가 없거나 두 개 이상 되면 컴파일 오류.(자바 8이상)

 

 

@Autowired 애노테이션을 이용한 의존 자동 주입

 

 

xml 파일에서 annotation-config.

이전 코드보다 훨신 간결하게 프로퍼티나 생성자 부분 없이 깔끔해졌다.

 

 

 

@Autowired 애노테이션으로 인해 코드가 더깔끔해짐 (위-애노테이션 / 아래-프로퍼티&생성자방식)

 

 

@Qualifier 애노테이션을 이용한 의존 객체 선택

 

package member.dao;

public class GuestDao implements Dao {

	@Override
	public void insert() {
		System.out.println("게스트 회원 정보 데이터베이스 저장");

	}

	@Override
	public void select() {
		System.out.println("게스트  회원 정보 검색");
	}

	@Override
	public void delete() {
		System.out.println("게스트  회원 정보 삭제");

	}

	@Override
	public void update() {
		System.out.println("게스트 회원 정보 수정");
	}

}

memberDao를 복사해서 GuestDao를 만들어준 뒤 실행하면 dao가 두개라서 에러가 난다.

 

Qualifier를 이용해서 value값을 설정해주고 클래스에서 Qulifier 어노테이션으로 지정해준 후 Main 실행

 

@Autowired 의 필수 여부 지정

 

주석처리 하니 Dao가 없어서 에러가난다 (당연..)

 

없더라도 인스턴스는 생성되도록 한다.

대부분은 꼭 있어야하는 Dao같은 상황에 사용하지만, 존재의 유무를 확인할 때 등등 정리해서 쓰면 좋다.

 

 

 

@Resource 애노테이션을 이용한 자동 의존 주입

 

id를 name으로 써서 구별한다.

그러나 타입으로 구별하는 @autowired를 더 자주사용한다.

타입을 맞추는 것이 더 정확하고 에러가 덜 나기 때문이래나 뭐래나.. 암튼 그렇다!

자동 주입과 명시적 의존 주입 설정이 함께 사용되는 경우 명시적인 의존 주입 설정이 우선한다

 

.

 

 

 

 

[Spring] 의존객체 자동 주입(Automatic Dependency Injection), @Autowired, @Resource, @Inject

| 의존객체 자동 주입(Automatic Dependency Injection) 의존 객체 자동 주입(Automatic Dependency Injection)은 스프링 설정파일에서  혹은  태그로 의존 객체 대상을 명시하지 않아도 스프링 컨테이너가 자..

xzio.tistory.com

 

'spring' 카테고리의 다른 글

[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08
[스프링] MVC : 패턴  (0) 2021.01.08
[스프링] 자바 프로젝트를 메이븐 기반의 프로젝트로 변환하기  (0) 2021.01.06
[스프링] 기본 설정  (0) 2021.01.05
[스프링] 설치  (0) 2021.01.05

자바 프로젝트를 메이븐 기반의 프로젝트로 변환하기

 

자바 프로젝트 생성 후 Convert to Maven Project > pom.xml이 생성된다.

 

mvnrepository.com/artifact/org.springframework/spring-context/3.1.1.RELEASE

에서 버전에 맞는 것을 pom.xml에 넣어주면 이렇게 생기긔..

 

 

'spring' 카테고리의 다른 글

[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08
[스프링] MVC : 패턴  (0) 2021.01.08
[스프링] DI / xml 설정파일 / 어노테이션  (0) 2021.01.06
[스프링] 기본 설정  (0) 2021.01.05
[스프링] 설치  (0) 2021.01.05

[app이름] firstspring이 context경로가 된다.

 

생성 하니까 필요한 라이브러리를 스프링에서 다운시켜주는 중이긔

 

 

 

 

이런 것들을 버전들을 버전에 맞게 수정해주어야 한다.

여기서는 자바만 해주었는데 나중에 스프링도 맞춰줘야함

 

 

 

 

필요한 라이브러리들은 .m2 폴더에 저장되어 있다.

 

 

 

mvnrepository.com/artifact/commons-fileupload/commons-fileupload/1.4

 

pom.xml 파일에 필요한 라이브러리를 복사해서 추가해주면 이 라이브러리를 자동으로 또 다운로드 한다.

똑똑하게 필요한 commons-io 까지 알아서 라이브러리 추가해줌!!!

 

 

 

 

 

 

JRE 시스템 라이브러리에서 우클릭 > 빌드패스 > configure웅앵 들어가서 버전에 맞게 설정해준다.

 

 

런타임해서 제대로 뜨면 끗~

 

 

자바 언어로 수정 하면 아래처럼 뜸

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

 

repo.spring.io/release/org/springframework/spring-context/

mvnrepository.com/search?q=spring

mvnrepository.com/search?q=fileupload

spring.io/tools

 

 

1. JDK 설치

2. 이클립스 설치

3. mysql 설치

 

 

방법1 - Spring Tool Suite(STS 설치) > 실행

 

github.com/spring-projects/toolsuite-distribution/wiki/Spring-Tool-Suite-3

방법2 - 이클립스 마켓플레이스에서 설치 

 

.

다시 시작!

 

 

 

spring과 이클립스 둘 다 사용이 가능하다.

 

STS 설정

 

삭제
삭제

 

workspace, spelling, web-css/html/jsp에서 UTF-8로 설정해준다.

가입후 지역설정은 서울로 해놓는다.

  

 

EC2 – 키페어 설정

 

 

키페어 설정은 EC2 – 네트워크 및 보안 탭의 키페어 키페어 생성에서 할 수 있다.

 

 

키페어는 지역 이름 프로젝트 명등 알아보기 쉬운 이름으로 한다.

파일형식은 pem을 선택해준다.

 

 

키페어가 생성 되면

 

 

  

Pem 파일이 생성되는데,

자주쓰게 되므로 알아보기 쉬운 폴더에 놓는 것이 좋다.

 

 

 

EC2 – 인스턴스 생성

 

EC2의 인스턴스에서 인스턴스 시작을 누른다.

 

 

 

 

무료 서비스를 사용할 것이므로 프리티어를 체크하고 원하는 타입을 골라준다.

인스턴스 유형에 선택에서 또 원하는 유형을 선택해준다.

 

검토 및 시작을 눌러도 되지만 인스턴스 세부 정보 구성을 누를 수도 있다.

세부 정보 구성은 다음과 같다.

 

 

 

 

 

검토가 완료되면 시작하기를 눌러준다. (여기서는 다른 설정은 하지 않았다)

 

 

 

시작하기를 누르면 키 페어를 선택할 수 있는데 앞서 생성해준 키페어를 선택해준다.

 

무료 서비스를 이용하려면 예상요금 알림 받기에서 필요한 것들을 체크해주는 것이 좋다.

 

 

인스턴스가 생성되었다.

 

 

키페어 putty

https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html

에 들어가서 putty.zip을 다운받는다.

 

 

 

 

 

압축을 풀면 다음과 같다.

 

Puttygen.exe를 실행한 후 다운 받았던 pem파일을 불러오고 private key를 누른다

같은 폴더에 pem파일이 ppk파일로 바뀐 것을 볼 수 있다.

 

그다음 putty.exe를 실행시켜 준뒤 다음과 같이 입력하는데 이때 IP

Aws 인스턴스에서 퍼블릭ip주소이다.

 

 

 

그다음 auth로 들어가서 아까 만들어두었던 ppk 파일을 등록해준다.

 

다시 세션으로 이동하여 이름을 지정해 save해주면 더 편하게 사용할 수 있다.

 

 

올바르게 설정을 완료했다면 실행 시 이러한 창이 뜬다.

 

 

 

Root로 들어가기 sudo su-

 

Root로 들어가려면 sudo su – 라고 입력되고 Exit를 치면 나와진다.

 

 

 

자바설치

 

 

yum list java*를 입력해서 설치할 수 있는 리스트를 확인하고,

 

yum install 설치할java파일명 우클릭 한 뒤(이름이복사된다) 설치시작! y누르면 설치완료

 

 

 

 

설치 후 java -version을 입력하면 자바버전을 확인할 수 있다.

 

 

톰캣 설치

Yum list * 로 설치할 수 있는 것들을 확인할 수 있고

 

yum list tomcat*을 치면 톰캣관련 설치가능한 목록을 볼 수 있다

(available packages)

 

 

 

이 중에서 tocattomat-admin-webapps, tomcat-webapps를 설치해준다.

설치 방법은 yum install ~ 로 아래와 같이 치면 된다.

 

그 뒤 톰캣 권한 설정을 위해 아래와 같이 쳐주는데

아무런 응답이 없으면 에러가 나지 않고 제대로 실행되고 있다는 뜻이다.

[root@ip-172-31-28-56 tomcat8]# cd /usr/share/tomcat8
[root@ip-172-31-28-56 tomcat8]# chgrp -R tomcat /usr/share/tomcat8
[root@ip-172-31-28-56 tomcat8]# chown -R tomcat webapps/ work/ temp/ logs/
[root@ip-172-31-28-56 tomcat8]# find conf webapps -type d -exec chmod 755 {} +
[root@ip-172-31-28-56 tomcat8]# find conf webapps -type f -exec chmod 644 {} +
[root@ip-172-31-28-56 tomcat8]# find logs temp work -type d -exec chmod 750 {} +
[root@ip-172-31-28-56 tomcat8]# find logs temp work -type f -exec chmod 640 {} +
[root@ip-172-31-28-56 tomcat8]# service tomcat8 restart

ls -al을 입력하면 설치된 설치된 것들을 볼 수있다.

 

 

Service tomcat status라고 쳤을 때 초록색으로 active(running)이라고 나오면

제대로 돌아가고 있는 것을 확인할 수 있다.

접근을 위해 EC2 – 보안그룹으로 들어가 인바운드 규칙을 편집해준다.

유형 사용자지정TCP, 소스유형 위치무관 , 포트범위는 8080으로 규칙을 추가해준다.

인바운드 규칙을 추가해주고 8080포트로 접속하면 이러한 화면이 뜬다.

(인바운드 규칙 추가전에는 페이지 이동X)

 

 

 

 

 

 

 

배포하기

 

https://filezilla-project.org/download.php에서 파일질라를 다운받아준다.

 

Putty와 마찬가지로 퍼블릭ip주소를 복사해온다.

 

사이트 관리자 창을 열어 아래와 같이 입력해주는데,

호스트는 앞서 복사한 ip 주소이며, 키 파일은 만들어둔 ppk파일을 불러오면 된다.

 

 

 

확인을 누르고 다시 사이트 관리자를 켠 후 연결해준다.

 

파일질라에서 보여지는 화면에 있는 파일들을 똑같이 확인해볼 수 있다.

 

 

우리는 원래 이 루트에 배포를 시켜야 하지만 권한이 없다.

 

 

그래서 먼저 여기(home/~이름)에 드래그를 해서 파일을 배포한 뒤 tomcat/webapps로 옮기는 방식을 쓴다.

 

 

 

 

 

먼저 배포를 위해서 다이나믹 프로젝트를 export하여 war파일로 만들어준다. (이클립스)

 

그 다음 드래그를 통해 넣어준다.

Ex2-userls -al을 쳐보면 넣어준 파일들이 잘 들어가 있는 것을 확인할 수 있다.

 

Sudo su – 입력해서 관리자 페이지로 들어간뒤, Mv 파일명 이동루트로 파일을 보내준다.

파일명 변경도 가능한데 open.war로하면 open이 주소이다.

 

 

 

 

성공적으로 끝났다면 올려놓은 프로젝트가 제대로 실행되는 것을 확인할 수 있다

 

 

AWS 데이터베이스 생성

계속하기 > 나머진 체크X

다음 단계에서는 퍼블릭 액세스 가능성 예로 체크

 

 

 

 

 

워크벤치 켜준다. 계정생성

username과 비밀번호는 db생성할 때 만들었던 걸로..

hostname은 데이터베이스 정보에 있는 엔드포인트로 넣어준다

 

aws-admin들어가서 aia계정 생성해주고 (원래썼던 계정과 이름동일하게 해서 코드 수정을 줄였다)

스키마도 똑같이 open으로 생성하고 aws-aia계정에 권한을 주었다.

 

 

 

테이블 복사해서 넣기

 

복사할 mysql계정(여기서는 aia)에 들어가서 Data Export 해준다.

테이블만 내보낼 수도 있고 데이터를 같이 내보낼 수도 있음.

 

위와같이 덤프 폴더로 생성된다

 

복사 하려고 하는 (새로생성한 aws / 여기서는 aws-aia)

 

복사완료~

 

 

 

JAVA에서는 localhost 대신에 엔드포인트 주소로 변경

data.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<table border="1">
		<tr>
			<td>우유</td>
			<td>2000</td>			
		</tr>
		<tr>
			<td>홍차</td>
			<td>5000</td>			
		</tr>
		<tr>
			<td>커피</td>
			<td>5000</td>			
		</tr>
		
		
	</table>

</body>
</html>

ajax-1.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<!-- 제이쿼리 DSK로드 -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
	$(document).ready(function(){
		//alert('onload');
		$.ajax('data.html',{
			success : function(data){
				$('body').append(data);	
			}
			
		});
		
	});

</script>
</head>
<body>
	<h1>가격표</h1>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<!-- 제이쿼리 DSK로드 -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
	$(document).ready(function() {
		$.ajax({
			url : 'data.html',
			success : function(data) {
				$('body').append(data);
			}
		});
	});
</script>
</head>
<body>
	<h1>가격표</h1>
</body>
</html>

 

parameter.jsp

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

<div> 이름 : ${param.pname} </div>
<div> 가격 : ${param.price} </div>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<!-- 제이쿼리 DSK로드 -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
	$(document).ready(function() {	
		$.ajax({
			url : 'parameter.jsp',
			type : 'GET', // get post put delete
			data : {
				pname : '우유',
				price : 2000,
				
			},
			success : function(data){
				$('body').append(data);
			}
			
		});
	});
</script>
</head>
<body>
	<h1>가격표</h1>
</body>
</html>

 

위에것을 동적으로 만들기

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<!-- 제이쿼리 DSK로드 -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>

$(document).ready(function(){
    //alert('onload');
    $('input:button').click(function(){
  	  $.ajax({
  	    	url : 'parameter.jsp',
  	    	type : 'get', // http method get, post, put, delete
  	    	data : {	
  	    		pname: $('#pname').val(),
  	    		price: $('#price').val()
  	    	},
  	    	success : function(data) {
  				$('body').append(data);
  			}
  	     }); 
    });     
  
 });


</script>
</head>
<body>
	<h3>제품등록</h3>
	이름 <input type="text" id="pname"><br>
	가격 <input type="number" id="price"><br><br>
	<input type="button" value="등록"><br>
	<hr>
	<br>
	<h1> 가격표</h1>
</body>
</html>

 

idcheck.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page trimDirectiveWhitespaces="true" %>
<!-- 공백제거 -->
${param.uid eq 'cool'? 'N' : 'Y'}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<!-- Jquery SDK 로드 -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>

<script>

	$(document).ready(function(){
		$('#uid').focusin(function(){
			//alert('focusin');
			//$('#msg').html('사용할수 있는 아이디 입니다.');
			$('#msg').addClass('display_none');
			$('#msg').removeClass('color_blue');
			$('#msg').removeClass('color_red');
			
		});
		
	//$('#idChkBtn').click(function(){
		
		$('#uid').focusout(function(){
			$.ajax({
				url : 'idcheck.jsp',
				type : 'post',
				data : {
					uid: $('#uid').val()
				}, 
				beforeSend : function(){
					console.log('beforeSend');
					$('#loaddingImg').removeClass('display_none');
				},
				success : function(data){
					
					//alert(data);
					if(data == 'Y') {						
						$('#msg').html('사용할수 있는 아이디 입니다.');
						$('#msg').removeClass('display_none');
						$('#msg').addClass('color_blue');
					} else {
						$('#msg').html('사용할수 없는 아이디 입니다.');
						$('#msg').removeClass('display_none');
						$('#msg').addClass('color_red');
					}
					
					
				},
				error : function(request, status, error){
					console.log('request', request);
					console.log('status', status);
					console.log('error', error);
				},
				complete : function(){
					
				setTimeout(function(){
						$('#loaddingImg').addClass('display_none');
					}, 3000);
					
				}
			});
			
		});
		
	});

</script>

<style>
	
	.display_none {
		display: none;
	}
	
	.display_block {
		display: block;
	}
	
	.color_red {
		color : red;
	}
	.color_blue {
		color: blue;
	}
	
	/* #msg {
		display: none;
	} */
	 
</style>
</head>
<body>

	id <input type="text" id="uid"> 
	<input type="button" id="idChkBtn" value="아이디 체크">
	<div id="msg"  class="display_none"></div><br>
	<img id="loaddingImg" class="display_none" alt="loadding" src="loading.gif">
 
</body>
</html>

 

serialize / serializeArray

- 입력받는 값이 많을수록 편리하며 id가 아닌 name으로 캐스팅 한다.

 

- parameter.jsp는 위에 있음

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<!-- 제이쿼리 DSK로드 -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>

$(document).ready(function(){
	
		     
	     $('#myform').submit(function(event){
	    	 
	    	 console.log($(this).serialize()); // input 파라미터 쿼리스트림을 문자열로 처리
	    	 console.log($(this).serializeArray());
	    	 
	    	 //입력받는게 많을수록 더 편리하다. id가아닌 name으로 캐스팅한다.
	    	 $.ajax({
	    		 url : 'parameter.jsp',
	    		 data : $(this).serialize(),
                 // data : data : $(this).serializeArray()로 받아도 괜찮음
	    		 success : function(data){
	    			  $('body').append(data)
	    			 
	    		 }
	    	
	    	 });
	 		return false;
	     });
  
 });


</script>
</head>
<body>
	<h3>제품등록</h3>
	<form id="myform">
	이름 <input type="text" id="pname" name="pname"><br>
	가격 <input type="number" id="price" name="price"><br><br>
	<input type="submit" value="등록"><br>
	</form>
	<hr>
	<br>
	<h1> 가격표</h1>
	
</body>
</html>

 

 

 

tenlie10.tistory.com/31

 

[TOMCAT | 톰캣] tomcat서버 에러 발생시 해결 방법(tomcat 7 failed to start in eclipse)

tomcat서버 에러 문제는 무조건 아래 5가지 원인에 기인한다. 1. web.xml 에러 servlet등록이 잘못되어 있을 때를 말한다. servlet-name, servlet-classm url-pattern을 오타없이 정확히 기입했는지 확인하자. 2...

tenlie10.tistory.com

 

tomcat서버 에러 문제는 무조건 아래 5가지 원인에 기인한다. 

 

 

1. web.xml 에러

servlet등록이 잘못되어 있을 때를 말한다. servlet-name, servlet-classm url-pattern을 오타없이 정확히 기입했는지 확인하자.


2. 서블릿 어노테이션

생성한 servlet의 어노테이션에 오타가 있을 경우 서버가 시작되지 않는다. 때문에 어노테이션 부분을 잘못 썼는지 다시 한번 확인해 보자.


3. 포트번호(8080) 충돌

기본설정 포트번호인 8080에 다른 서버가 잡혀 있어서 톰캣서버가 이 포트번호에 접속하려는 경우 충돌이 발생하면 역시 에러가 난다. 톰캣의 conf폴더의 server.xml파일에서 포트번호를 다른 번호로 변경해주자(보통 8090이나 80를 사용한다).


4. 프로젝트 클린 안해서

프로젝트를 주기적으로 클린해주지 않으면 가끔씩 서버가 꼬이는 경우가 있다. 때문에 프로젝트 클린 또한 한 번 실시해주도록 한다.


5. 프로젝트에 서버 업로드 안해서

웹프로젝트에 서버가 업로드 되지 않아서 발생할 경우도 있다(이 때는 프로젝트 파일들의 http관련 클래스에 빨간줄이 그어져 있을 것이다). 해당 프로젝트를 우클릭 한 후 properties => java build path=> libraries => add library => server runtime => tomcat7을 등록한다.



'memo' 카테고리의 다른 글

[스프링] ajax 참고  (0) 2021.01.29
RESTCLIENT  (0) 2021.01.28
[스프링] mvc패턴에 관한 블로그  (0) 2021.01.08
Server Tomcat v8.5 Server at localhost failed to start  (0) 2020.12.23
과제  (0) 2020.11.14
이클립스(Eclipse) 개발환경 / uft-8  (0) 2020.11.02
있는 txt 뒤에 이어쓰기  (0) 2020.10.31

archive.apache.org/dist/commons/fileupload/binaries/

 

Index of /dist/commons/fileupload/binaries

 

archive.apache.org

commons.apache.org/proper/commons-io/download_io.cgi

 

Commons IO – Download Apache Commons IO

Download Apache Commons IO Using a Mirror We recommend you use a mirror to download our release builds, but you must verify the integrity of the downloaded files using signatures downloaded from our main distribution directories. Recent releases (48 hours)

commons.apache.org

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일 업로드</title>
</head>
<body>

	<h1>파일 업로드</h1>
	
	<!-- 
				필수 1 : form tag 안의 속성 method="post" 
				필수 2 : form tag 안의 속성 enctype="multipart/form-data"
	 -->
	 
	<form action="upload.jsp"  method="post" enctype="multipart/form-data" >
	
		<input type="text" name="title"><br>
		
		<!-- 필수3 :  업로드 할 파일을 선택할 수 있는 input -->
		<input type="file" name="file"><br>
		
		<input type="submit">
	</form>
	

</body>
</html>

upload.jsp

<%@page import="java.io.File"%>
<%@page import="java.util.Iterator"%>
<%@page import="org.apache.commons.fileupload.FileItem"%>
<%@page import="java.util.List"%>
<%@page import="org.apache.commons.fileupload.disk.DiskFileItemFactory"%>
<%@page import="org.apache.commons.fileupload.servlet.ServletFileUpload"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	boolean result = false;
	
	// 파라미터 이름이 title인 데이터를 저장할 변수
	String title = null;
	// 1. multipart/form-data 여부 확인
	boolean isMultipart = ServletFileUpload.isMultipartContent(request);
	
	if(isMultipart){
		
		// 2. 업로드 할 파일을 보관 FileIte의 Factory 설정
		DiskFileItemFactory factory = new DiskFileItemFactory();
		
		// 3. 요청을 처리(form 안의 input 들을 분리 )할 ServletFileUpload 생성
		ServletFileUpload upload = new ServletFileUpload(factory);
		
		// 4. 사용자의 요청을 파싱(데이터를 추출해서 원하는 형식으로 만드는것)
		// FileItem ->  사용자의 요청 파라미터인 input의 객체
		List<FileItem> items = upload.parseRequest(request);
		
		Iterator<FileItem> itr = items.iterator();
		
		while(itr.hasNext()){
			
			FileItem item = itr.next();
			
			// 폼 필드와 파일 을 구분해서 처리
			if(item.isFormField()){
				
				// true -> type=file 인 것을 제외한 나머지 필드
				// 필드 이름, 파라미터 이름
				String fName = item.getFieldName();
				if(fName.equals("title")){
					title = item.getString("utf-8");
				}
				
				request.setAttribute("title", title);
				
			} else {
				
				// false -> type=file 인 필드
				String fName = item.getFieldName(); 		// 필드의 이름
				String userFileName = item.getName();		// 파일의 이름
				String contentType = item.getContentType();	// 컨텐트 타입
				long fileSize = item.getSize();				// 파일의 바이트 사이즈
				
				System.out.println("필드 이름 : "+fName);
				System.out.println("파일 이름 : "+userFileName);
				System.out.println("컨텐츠 타입 : "+contentType);
				System.out.println("File size : "+fileSize);
				
				// 파이을 서버의 특정 폴더에 저장(쓰기)
				if(!userFileName.isEmpty() && fileSize>0){
					
					// 파일을 실제 저장할 폴더의 시스템 경로
					String dir = request.getSession().getServletContext().getRealPath("/upload");
					System.out.println(dir);
					
					// 저장할 경로를 File 객체로 생성
					File saveFilePath = new File(dir);
					
					// 폴더가 존재하지 않으면 폴더를 생성
					if(!saveFilePath.exists()){
						saveFilePath.mkdir();
					}
					
					// 파일 쓰기(저장)
					item.write(new File(saveFilePath, userFileName));
					System.out.println("파일 저장 완료!");
					
					// 완료시에 전달할 데이터
					request.setAttribute("saveFileName", userFileName);
					
				}
				
			}
			
		}
		// 정상 처리
		result = true;
		request.setAttribute("result", result);
		
	}
	
	
		
%>

<jsp:forward page="upload_view.jsp"/>

upload_view.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>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<c:if test="${result}">
		<h1>파일 업로드가 되었습니다.</h1>
		<h3>
			TITLE : ${title}<br> 파일 이름 : ${saveFileName}
		</h3> 
		<img alt="프로필 사진" src="<c:url value="/upload/${saveFileName}"/>">
	</c:if>
	
	<c:if test="${!result}">
		<h1>파일 업로에 문제가 발생했습니다. 다시 시도해주세요.</h1>
	</c:if>

</body>
</html>

'JAVA > Jsp&Servlet' 카테고리의 다른 글

[JSP] JSTL - fmt  (0) 2020.12.23
[JSP] JSTL 설치 및 사용 / core <c:~>  (0) 2020.12.23
[JSP] 표현언어 EL / Expression Language  (0) 2020.12.23
[JSP] mysql JDBC  (0) 2020.12.18
[JSP] session 기본 객체  (0) 2020.12.18
[JSP] 쿠키처리를 위한 유틸리티 클래스 만들기  (0) 2020.12.17
[JSP] 쿠키  (0) 2020.12.17

idollee.tistory.com/42

 

이클립스 Server Tomcat v8.5 Server at localhost failed to start 오류 발생시 (화병사망 막는법)

이클립스를 사용해 웹 프로그래밍을 하던 중 JSP파일이나 Servlet파일 실행 시 위와 같은 오류가 뜨며 tomcat서버가 실행을 거부한다. 문제가 발생하여 실행하지 못했다는데 뭐가 문제인지는 안알려

idollee.tistory.com

 

todl77.tistory.com/3

 

Server Tomcat v8.5 Server at localhost failed to start.

톰캣 서버를 더블클릭 후, Publish module contexts to separate XML files 체크박스를 클릭해준다. ※ 참고로 Port Name에 있는 항목들의 Port Number도 각각 다 달라야 한다.※ 만약, 이클립스 서버 포트 충돌..

todl77.tistory.com

 

 

 

 

'memo' 카테고리의 다른 글

RESTCLIENT  (0) 2021.01.28
[스프링] mvc패턴에 관한 블로그  (0) 2021.01.08
tomcat서버 에러 발생시 해결 방법  (0) 2020.12.28
과제  (0) 2020.11.14
이클립스(Eclipse) 개발환경 / uft-8  (0) 2020.11.02
있는 txt 뒤에 이어쓰기  (0) 2020.10.31
url  (0) 2020.10.28

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	1. <fmt:formatNumber value="1000000"/> <br>
	2. <fmt:formatNumber value="1000000" groupingUsed="false"/><br>
	3. <c:set var="number" value="123456789"/>
	 	<fmt:formatNumber value="${number}"/><br>
	4. <fmt:formatNumber var="fNumber" value="${number}"/> 
		 ${fNumber}<br>
		 
	통화 :  <fmt:formatNumber value="${number}" type="currency" currencySymbol="원"/> , <fmt:formatNumber value="${number}" type="currency"/><br>
	퍼센트 :  <fmt:formatNumber value="${number/50000000}" type="percent"/><br>
	패턴 : <fmt:formatNumber value="${number}" pattern="000,000,000.00"/>
		

</body>
</html>

 

<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>


<%
	request.setAttribute("now", new Date());
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>


 
<%-- 전부 홍콩 시간대로 바귐 <fmt:timeZone value="Hongkong"> --%>
	<b>date</b><br>
	${now}<br>
	<fmt:formatDate value="${now}"/><br>
	<fmt:formatDate value="${now}" type="date"/><br>
	<fmt:formatDate value="${now}" type="date" dateStyle="full"/><br>
	<fmt:formatDate value="${now}" type="date" dateStyle="short"/><br>
	<b>time</b><br>
	<fmt:formatDate value="${now}" type="time"/><br>
	<fmt:formatDate value="${now}" type="time" timeStyle="full"/><br>
	<fmt:formatDate value="${now}" type="time" timeStyle="short"/><br>
	<b>both</b><br>
	<fmt:formatDate value="${now}" type="both"/><br>
	<fmt:formatDate value="${now}" type="both" dateStyle="full" /><br>
	<fmt:formatDate value="${now}" type="both" dateStyle="short" timeStyle="short"/><br>
	<b>패턴</b> <br>
	<fmt:formatDate value="${now}" pattern="z a h:mm"/><br>
	<fmt:formatDate value="${now}" pattern="hh:mm"/><br>
	<fmt:formatDate value="${now}" pattern="yyy-MM-dd h:mm"/><br>
	<fmt:formatDate value="${now}" pattern="yyy-MM-dd h:mm" timeZone="Hongkong"/><br>
	
<%-- </fmt:timeZone> --%>
	
</body>
</html>

'JAVA > Jsp&Servlet' 카테고리의 다른 글

[JSP] FileUpload  (0) 2020.12.24
[JSP] JSTL 설치 및 사용 / core <c:~>  (0) 2020.12.23
[JSP] 표현언어 EL / Expression Language  (0) 2020.12.23
[JSP] mysql JDBC  (0) 2020.12.18
[JSP] session 기본 객체  (0) 2020.12.18
[JSP] 쿠키처리를 위한 유틸리티 클래스 만들기  (0) 2020.12.17
[JSP] 쿠키  (0) 2020.12.17

+ Recent posts