아두이노란 무엇인가?

- 초소형 컴퓨터 ( 마이크로 컨트롤러 )

- 아주 제한적인 처리장치 / 메모리 / 저장공간 / 입출력장치를 가짐

- 이탈리아의 이브레아 마을에서 마시모 반지라는 아키텍트에 의해서 개발되었음.

 

아두이노는 다양한 버전이 존재한다.

- 전문가들이 사용하는 Mega 보드

- 초급자들이 사용하는 Explora 보드

- Wearable 목적의 Lily pad

- 가장 Basic 하고 범용성 있는 UNO

 

아두이노 동작까지의 절차

1> 물리적 아두이노 보드에 부품를 연결한다.

2> 어떤 부품에 어떤 신호와 명령을 보낼지 소스코드를 작성한다. ( C언어 )

3> 작성 완료된 소스코드를 컴파일하여 아두이노 메모리에 로딩해서 실행

 

임베디드 시스템에 적용

- 임베디드 시스템이란? ( 내장시스템 )

- 전자기기 내에 탑재되어서 정해진 일정 행동을 수행하는 목적의 시스템

- ex) 냉장고 / 에어컨


아두이노 시뮬레이팅 사이트

 

https://www.tinkercad.com/joinclass/5GBQYGHH59Z6

 

Classroom login

 

www.tinkercad.com

 

 


V = I * R

아두이노 기본 전압 5 V 

LED 필요 전압 3V

필요전류 10A

제품 구성중 비슷한 것 : 330옴

1초씩 깜박거리게

 

12번 포트에서 11번으로 변경시, 코드에서 일일히 찾아 변경하기 번거로움

 

전역 변수로 만들기 (C언어 개념, 자바로는 public static)



출력을 위한 세팅

int led = 11;

void setup()
{
  Serial.begin(9600);
  pinMode(led, OUTPUT);
}

void loop()
{
  Serial.println("Hello");
}


AnalogWrite

 

PWM pin : 디지털값을 아날로그로 변경

 

 

REG 최대값 255

void loop()
{
  analogWrite(led,100);
}

 

디지털 핀( ~이 없는 번호 )으로 옮기면 정상 동작하지 않음

 


LED RGB

 

PW로 연결했으므로 AnalogWrite 가능


난수 생성

(C 언어에서는 난수값의 패턴이 존재, 완전한 난수라고 보기 어려움)

 

void setup()
{
	Serial.begin(9600);
}

void loop()
{
  randomSeed(analogRead(0));
  int randVal = random(255); // 0~255 사이의 난수
  Serial.println(randVal);
  delay(1000);
}

randomSeed와 random 함께 사용


1초에 한번씩 랜덤한 밝기값을 가지는 LED 만들기

 


RANDOM RGB

int pin[3] = {11,10,9};

void setup()
{
  for(int i = 0; i<3; i++){
  	pinMode(pin[i],OUTPUT);
  }
	Serial.begin(9600);
}

void loop()
{
  for(int i=0; i<3; i++){
  randomSeed(analogRead(0));
  int randVal = random(255); // 0~255 사이의 난수
  Serial.println(randVal);
  analogWrite(pin[i],randVal);
  }
  delay(1000);
}

3개의 LED 중 하나가 랜덤하게 켜지는 프로그램

 

int pin[3] = {11,10,9};

void setup()
{
  for(int i = 0; i<3; i++){
  	pinMode(pin[i],OUTPUT);
  }
	Serial.begin(9600);
}

void loop()
{
  
  randomSeed(analogRead(0));
  int randVal = random(3); // 0~2 사이의 난수
  Serial.println(randVal);
  digitalWrite(pin[randVal],HIGH);
  delay(1000);
  digitalWrite(pin[randVal],LOW);
  
}


보드가 깔려있는 부품을 쉴드라고 한다.

 

와이파이 쉴드 이더넷 쉴드 (칩셋위에 있는 부품)

'디지털 컨버전스 > Arduino' 카테고리의 다른 글

[아두이노] map() / 밝기 측정  (0) 2020.06.19
[아두이노] 포토 레지스터  (0) 2020.06.19
[아두이노] 피에조  (0) 2020.06.19
[아두이노] 스위치  (0) 2020.06.18
[아두이노] IDE  (0) 2020.06.16

mkdirs()사용해서 log라는 디렉토리를 생성하도록 하고 있습니다.

mkdir()와 차이점은 C드라이브에 temp라는 폴더가 없는 경우 temp 폴더를 생성하고 그 안에 log폴더를 생성합니다.

지정한 경로에 폴더가 없는 경우 폴더를 생성하여 마지막 지정한 폴더까지 생성해 줍니다.

package kh.spring.controller;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.google.gson.Gson;

import kh.spring.dto.BoardDTO;
import kh.spring.dto.FileDTO;
import kh.spring.dto.MemberDTO;
import kh.spring.service.BoardService;

@Controller
@RequestMapping("/board/")
public class BoardController {

	@Autowired
	private BoardService bservice;

	@Autowired
	private HttpSession session;

	@RequestMapping("test")
	public String test() {
		return "board/test";
	}


	@RequestMapping("toBoard")
	public String toBoard(HttpServletRequest request) throws Exception {
		return "board/boardListView";
	}


	@RequestMapping(value="boardListAjax",produces="application/json;charset=utf8")
	@ResponseBody
	public Object boardListAjax(HttpServletRequest request)  throws Exception {
		int cpage = Integer.parseInt(request.getParameter("cpage"));
		//		System.out.println("boardListAjax 가 받은 cpage : " + cpage );
		List<BoardDTO> list = bservice.selectByPageNo(cpage);
		//		System.out.println("List<BoardDTO> list의 사이즈 : "+list.size());
		//클라이언트는 JSON으로 받는게 좋음 : List<BoardDTO>를 JSON으로
		String respArr = new Gson().toJson(list);
		//		System.out.println("String respArr : "+respArr);
		return respArr;
	}


	@RequestMapping("toBoardContents")
	public String toBoardContents(HttpServletRequest request) throws Exception {
		BoardDTO dto = new BoardDTO();
		dto.setSeq(Integer.parseInt(request.getParameter("seq")));
		List<BoardDTO> bdtoList = bservice.select(dto);
		request.setAttribute("bdtoList", bdtoList);
		
		List<FileDTO> fileList = bservice.selectFileByPSeq(dto.getSeq());
		request.setAttribute("fileList", fileList);
		return "board/boardContentsView";
	}
	@RequestMapping("toBoardWrite")
	public String toBoardWrite() throws Exception {
		return "board/boardWriteView";
	}


	@RequestMapping("boardWrite")
	public String boardWrite(HttpServletRequest request, MultipartFile[] files) throws Exception {
		MemberDTO loginInfo = (MemberDTO)request.getSession().getAttribute("loginInfo");
		String id = loginInfo.getId();
		System.out.println("게시판에 글 쓰는 id : "+id);
		String writer = loginInfo.getName();
		String title = request.getParameter("title");
		String contents = request.getParameter("contents");
		String category = request.getParameter("category");
		String ip_address = request.getRemoteAddr();
		BoardDTO bdto = new BoardDTO(0,writer,Timestamp.valueOf(LocalDateTime.now()),0,title,category,id,contents,ip_address);
		bservice.boardWrite(bdto);
		
		String filePath = session.getServletContext().getRealPath("upload/"+id);
		 System.out.println("filePath : "+filePath);
		for(MultipartFile file : files) {
			if(!file.isEmpty()) {
				UUID uuid = UUID.randomUUID();
				File tempFilePath = new File(filePath);
				if(!tempFilePath.exists()) {
					System.out.println(tempFilePath+"가 없으므로 생성합니다.");
					tempFilePath.mkdirs();}
				String systemFileName = uuid.toString()+"_"+file.getOriginalFilename();
				File targetLoc = new File(filePath+"/"+systemFileName);
				System.out.println("targetLoc : "+targetLoc);
				file.transferTo(targetLoc);
				
				String original_file_name = file.getOriginalFilename();
				String stored_file_name = systemFileName;
				int file_size = (int) file.getSize();
				System.out.println("file_size : "+file_size);
				FileDTO fdto = new FileDTO(0,0,original_file_name,stored_file_name,file_size,Timestamp.valueOf(LocalDateTime.now()),id,"n");
				bservice.fileWrite(bdto, fdto);
			}
		}
		return "board/boardListView";
	}

	
	@RequestMapping("downLoadFile")
	public void downLoadFile(int seq, HttpServletResponse resp) throws Exception {
		FileDTO fdto = bservice.getFileBySeq(seq);
		String filePath = session.getServletContext().getRealPath("upload/"+fdto.getUploader_id());
		System.out.println("filePath : "+filePath);
		File target = new File(filePath+"/"+fdto.getStored_file_name());
		try(DataInputStream dis = new DataInputStream(new FileInputStream(target));
		ServletOutputStream sos = resp.getOutputStream();){
				
		String fileName = new String(fdto.getOriginal_file_name().getBytes("utf8"),"iso-8859-1");	
			
		resp.reset();
		resp.setContentType("application/octet-stream");
		resp.setHeader("Content-disposition", "attachment;filename="+fileName+";");
		
		byte[] fileContents = new byte[(int)target.length()];
		dis.readFully(fileContents);
		
		sos.write(fileContents);
		sos.flush();
		}
	}

}

 

익명 채팅방

package kh.spring.controller;

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

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

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		logger.info("Welcome home! The client locale is {}.", locale);
		
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
		
		String formattedDate = dateFormat.format(date);
		
		model.addAttribute("serverTime", formattedDate );
		
		return "home";
	}
	
}
package kh.spring.chat;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/chat")
public class WebChat {

	private static Set<Session> clients = new HashSet<>();

	@OnOpen
	public void onConnect(Session client) {
		System.out.println(client.getId()+" 클라이언트가 접속했습니다.");
		clients.add(client);
	}

	@OnMessage
	public void onMessage(Session session, String message) {
		for(Session client : clients) {

			if(!client.getId().contentEquals(session.getId())) {

				Basic basic = client.getBasicRemote();
				try {
					basic.sendText(message);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}


	}

	@OnClose
	public void onClose(Session session) {
		clients.remove(session);
	}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
	overflow-y: auto;
	word-break: break-all;
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
	overflow-y: auto;
}
</style>
<script>

	
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")
		
		ws.onmessage = function(e){
			console.log(e.data);
			var line = $("<div>");
			line.append(e.data);
			$(".message-area").append(line);
		}

		
		
		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				$('.message-area').scrollTop($('.message-area')[0].scrollHeight);
				return false;
			}
		})

	})
</script>
</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>
	<!-- 웹소캣 라이브러리 추가 -->
		<dependency>
			<groupId>javax.websocket</groupId>
			<artifactId>javax.websocket-api</artifactId>
			<version>1.1</version>
		</dependency>
	

HTTP 프로토콜이 아니라 웹소캣으로 접속하기 때문에

ip 주소와 웹 정보를 가져올수없음

session configurator 

 

 

HTTPSessionConfigurator

object형을 리턴하기에 캐스팅 해줘야함

Map 방식

 

WebChat의 @ServerEndpoint 인자값 추가, 만든 httpSessionConfigurator 자료형 추가

핸드쉐이크로 만들어진 값이 config로 들어옴

 

다른 메서드에서도 쓸수 있도록

HomeController에서 session 사용 가능


서버에서 접속 url 수정 가능


package kh.spring.chat;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import kh.spring.config.HTTPSessionConfigurator;

@ServerEndpoint(value="/chat",configurator = HTTPSessionConfigurator.class)
public class WebChat {

	private static Set<Session> clients = new HashSet<>();
	private HttpSession session;

	@OnOpen
	public void onConnect(Session client, EndpointConfig config) {
		System.out.println(client.getId()+" 클라이언트가 접속했습니다.");
		clients.add(client);
		this.session = (HttpSession) config.getUserProperties().get("session");
	}

	@OnMessage
	public void onMessage(Session session, String message) {
		
		String id = (String)this.session.getAttribute("loginId");
		
		for(Session client : clients) {
			if(!client.getId().contentEquals(session.getId())) {
				Basic basic = client.getBasicRemote();
				try {
					basic.sendText(id+ " : "+message);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	@OnClose
	public void onClose(Session session) {
		clients.remove(session);
	}
}
package kh.spring.config;

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;

public class HTTPSessionConfigurator extends Configurator{

	@Override
    public void modifyHandshake(
    		ServerEndpointConfig sec, 
    		HandshakeRequest request, 
    		HandshakeResponse response) {
		
		HttpSession session = (HttpSession)request.getHttpSession();
		sec.getUserProperties().put("session", session);
        
    }

}
package kh.spring.controller;

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

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;


@Controller
public class HomeController {
	
	
	@Autowired
	private HttpSession session;
	

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {

		this.session.setAttribute("loginId", "Jack");
		
		return "home";
	}
	
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
	overflow-y: auto;
	word-break: break-all;
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
	overflow-y: auto;
}
</style>
<script>

	
	$(function() {
		var ws = new WebSocket("ws://192.168.60.7/chat")
		
		ws.onmessage = function(e){
			console.log(e.data);
			var line = $("<div>");
			line.append(e.data);
			$(".message-area").append(line);
		}

		
		
		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				$('.message-area').scrollTop($('.message-area')[0].scrollHeight);
				return false;
			}
		})

	})
</script>
</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>

동시성 오류

 

동기화 작업 필요

 

 

HashSet 에 동기화 작업을 할 수 있도록 업그레이드

일반 HashSet은 동시성에 대한 취약성이 있다.

 

 


에러 처리

 

연결 끊어버리기

	@OnError
	public void onError(Session session, Throwable t) {
		clients.remove(session);
	}

 

메세지를 보내는 중 한명이 나갈경우

for문이 도는 동안 정지

없는 사람에게 보낼 수 없음

 

	@OnMessage
	public void onMessage(Session session, String message) {
		
		String id = (String)this.session.getAttribute("loginId");
		
		synchronized(clients){
			for(Session client : clients) {
				if(!client.getId().contentEquals(session.getId())) {
					Basic basic = client.getBasicRemote();
					try {
						basic.sendText(id+ " : "+message);
					} catch (IOException e) {}
				}
			}
		}

	}

굳이 나간 사람 때문에 발생한 에러 메시지를 출력할 필요 없음

HTTP 프로토콜은 클라이언트가 요청하고 서버가 응답을 보내는게 기본

 

클라이언트가 req를 쓰면 다른 클라이언트에게 전달달

2번 클라이언트 입장에서는 req없이 서버에게 받는게 먼저

 

 

1. 원초적인 방법

각각의 클라이언트가 계속 리퀘스트를 쏘도록 함

submit, href 등으로 req 보내는 경우 페이지 전환 -> AJAX 활용

-> 서버 과부하

5초정도 딜레이를 준다면? 부하는 줄어들지만 사용이 불편


HTTP 말고 실시간으로 통신을 하기 위해

 socket을 활용

 

웹소캣 라이브러리 필요

		<!-- 웹소캣 라이브러리 추가 -->
		<dependency>
			<groupId>javax.websocket</groupId>
			<artifactId>javax.websocket-api</artifactId>
			<version>1.1</version>
		</dependency>

scope는 어디에 적용될지 정하는 태그 (dependency scope를 검색하면 설명 나온다)

생략하면 전체 적용

HTTP 프로토콜이 아닌 

WS (웹소캣)


읽는 순간 소캣 연결 요청

 

소캣 연결 요청 받는 위치

@OnOpen : 접속시 실행


웹소캣 프로토콜의 세션

import javax.websocket.Session;

Spring Bean이 아니기 떄문에 Autowired 못한다

 

 

client.getId() : 16진수 숫자

F5를 누를 때마다 페이지가 다시 로딩될때 웹소캣 새로 발급


<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script>
	$(function(){
		var ws = new WebSocket("ws://localhost/chat")
	})
</script>
<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
	position: absolute;
	margin: -250px 0 0 -250px;
	top: 50%;
	left: 50%;
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
}
</style>

</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>

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

<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
	
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
	overflow-y: auto;
	 word-break : break-all; 
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
	overflow-y: auto;
}
</style>
<script>

function updateScroll(){
	var element = document.getElementById("message-area")
}
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")

		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var msg = $(".input-area").html();
				var tr = $("<tr></tr");
				tr.append("<td>글쓴이 : " + msg);
				$(".message-area").append(tr);
				$(".input-area").html("");


			}
		})


	})
</script>
</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>

updateScroll 함수로 만들어 호출하는건 실패고 제이쿼리로 안에 넣은것 동작? 왜?


	$(function() {
		var ws = new WebSocket("ws://localhost/chat")

		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				updateScroll();
				return false;
			}
		})

	})

 

@OnMessage

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

<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
	overflow-y: auto;
	word-break: break-all;
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
	overflow-y: auto;
}
</style>
<script>

	
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")

		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				$('.message-area').scrollTop($('.message-area')[0].scrollHeight);
				return false;
			}
		})

	})
</script>
</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>

package kh.spring.chat;

import java.io.IOException;

import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/chat")
public class WebChat {

	@OnOpen
	public void onConnect(Session client) {
		System.out.println(client.getId()+" 클라이언트가 접속했습니다.");
	}
	
	@OnMessage
	public void onMessage(Session session, String message) {
		
//		System.out.println(session.getId()+" : "+message);
		
		Basic client = session.getBasicRemote();
		try {
			client.sendText(message);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	
}

말한 그대로 돌아옴 : 에코

 

내가 아니라 상대방에서 보내야 함!

 

 


 

클라이언트들의 접속 정보가 서버의 램에는 저장되지만 제어할 수 있는 정보는 모름

 

매개변수로 받고 매서드가 끝나면 사라짐

정보를 저장해 놔야함

몇명이 들어올지 모르기 때문에 배열은 부적절

 

세션아이디는 중복되서는 안된다 -> set으로 중복 방지

 

모든 사용자가 공유할 수 있도록 Set<Session> clients에  static을 줘야함

package kh.spring.chat;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/chat")
public class WebChat {

	private static Set<Session> clients = new HashSet<>();
	
	@OnOpen
	public void onConnect(Session client) {
		System.out.println(client.getId()+" 클라이언트가 접속했습니다.");
		clients.add(client);
	}
	
	@OnMessage
	public void onMessage(Session session, String message) {
		for(Session client : clients) {
			Basic basic = client.getBasicRemote();
			try {
				basic.sendText(message);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}	
	}
}


<script>

	
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")
		
		ws.onmessage = function(e){
			console.log(e.data);
			var line = $("<div>");
			line.append(e.data);
			$(".message-area").append(line);
		}

		
		
		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				$('.message-area').scrollTop($('.message-area')[0].scrollHeight);
				return false;
			}
		})

	})
</script>

 

내가 친 채팅과 출력되는 채팅이 중복 되는 경우, 하나만 출력되도록 하기

	@OnMessage
	public void onMessage(Session session, String message) {
		for(Session client : clients) {

			if(!client.getId().contentEquals(session.getId())) {

				Basic basic = client.getBasicRemote();
				try {
					basic.sendText(message);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}


	}

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

<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
	overflow-y: auto;
	word-break: break-all;
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
	overflow-y: auto;
}
</style>
<script>

	
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")
		
		ws.onmessage = function(e){
			console.log(e.data);
			var line = $("<div>");
			line.append(e.data);
			$(".message-area").append(line);
		}

		
		
		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				$('.message-area').scrollTop($('.message-area')[0].scrollHeight);
				return false;
			}
		})

	})
</script>
</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>
package kh.spring.chat;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/chat")
public class WebChat {

	private static Set<Session> clients = new HashSet<>();

	@OnOpen
	public void onConnect(Session client) {
		System.out.println(client.getId()+" 클라이언트가 접속했습니다.");
		clients.add(client);
	}

	@OnMessage
	public void onMessage(Session session, String message) {
		for(Session client : clients) {

			if(!client.getId().contentEquals(session.getId())) {

				Basic basic = client.getBasicRemote();
				try {
					basic.sendText(message);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}


	}

	@OnClose
	public void onClose(Session session) {
		clients.remove(session);
	}
}
더보기

 


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Home</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<style>
* {
	box-sizing: border-box;
}

.chat-box {
	width: 400px;
	height: 500px;
	margin: 100px auto;
	border: 1px solid #c9d8de;
	position: relative;
}

.message-area {
	padding: 20px;
	min-height: 400px;
	overflow-y: auto;
	background: #f0f9fd;
	width: 100%;
	height: 80%;
	word-wrap: break-word;
	word-break: break-all;
}

.input-area {
	width: 100%;
	height: 100px;
	overflow: auto;
}
</style>
<script>
		function updateScroll() {
			var element = document.getElementById("message-area");
			element.scrollTop = element.scrollHeight;
		}

		$(function() {
			
			var ws = new WebSocket("ws://175.125.124.73:11111//chat");
			ws.onmessage = function(e){
				var line = $("<div>");
				line.append(e.data);
				$(".message-area").append(line);
				updateScroll();
			}
			
			$(".input-area").on("keydown", function(e) {
				if (e.keyCode == 13) {
					
					if($(".input-area").html()=="" || $(".input-area").html()==" "){
						alert("글을 입력하세요.");
					}else {
					var text = $(".input-area").html();
					var line = $("<div>");
					line.append(text);
					$(".message-area").append(line);
					$(".input-area").html("");
					ws.send(text);
					updateScroll();
					return false;
				}
			}
			});

			

		});
	</script>


</head>
<body>
	<div class="chat-box">
		<div id="message-area" class="message-area"></div>
		<div id="input-area" class="input-area" contenteditable="true"></div>
	</div>

</body>
</html>

 

proceed 기능 수행 전에 홈화면으로 보내버리기

 

프로젝트 자체를 다른 pc에서 가져와서 톰캣 경로변경이 필요한경우

 

서버를 삭제하고 새로 만들기

 

 

 

JoinPoint

- PointCut 후보

- Advice 가 적용 될 수 있는 메서드

 

PointCut

- JoinPoint 중에서 실제 Advice를 적용하기 위해 선별해 낸 메서드

- PointCut Expression 을 통해 선별함

 

Advice

- 선별된 PointCut 메서드에 적용될 횡단기술

 

Weaving

- Advice를 PointCut


servlet-context.xml

logAdvisor를 빈으로 만들어 놓기

HomeController의 home 메서드(매개변수는 있을수도 없을수도)

pointcut 준비해놓기

before로 적용


aop:before


 

 

 

스프링이 갖고 있는 bean에서만 HttpSession만 Autowired 할 수 있다.

 

 

 


 

 

리퀘스트를 출력할 때

셋어트리뷰트 하지 않았으므로 null이 나올 것

 

 

before가 먼저 출력 후 메서드 실행

 

매개변수의 자료형과 개수를 모르기 때문에 오브젝트형 배열로 받는다.

지나가던 request 에 값 넣어놓기

 

 

 

범용성없는 예제코드

가도있던 코드는 낚아채서 추가처리 후 보낼 수 있다.

 

AOP는 강력하지만 오류도 많이 발생시키기 때문에 사용 패턴이 정해져 있다 (로그 남기기, 트랜젝션, 시큐리티)


aop:around

 

ProceedingJoinPoint : around 만 가질 수 있는 매개변수

JoinPoint 상속받아 기능을 모두 가짐

낚아챈 시점 (38번 라인)

39번에서 실행된 메서드의 리턴값이 돌아옴

 

어드바이스가 포인트컷매서드를 콜 한다.

 

 

성능체크 시( endtime - starttime ) around 사용 적절

 

 

ex. 보드컨트롤러에 있는 모든 메서드 성능체크 하기

 

모든 메서드에 적용되므로 범용성 있는 코드로 작성 할 것.

package kh.spring.aspect;

import java.text.SimpleDateFormat;

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

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.springframework.beans.factory.annotation.Autowired;

public class LogAdvisor {
	
	@Autowired
	private HttpSession session;

	// advice
	public void aopTest(JoinPoint jp) {
		Signature sign = jp.getSignature();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
		String currentTime = sdf.format(System.currentTimeMillis());
		
		Object[] args = jp.getArgs();
		HttpServletRequest req = (HttpServletRequest)args[0];
		req.setAttribute("request", "Hello AOP");

		System.out.println("===============");
		System.out.println(currentTime);
		System.out.println(jp.getTarget()); // Advice가 적용되어 실행되는 메서드의 클래스
		System.out.println(sign.getName());
		System.out.println("===============");
//		System.out.println(session.getAttribute("loginId"));
	}
	
	
	public Object aroundTest(ProceedingJoinPoint pjp) throws Throwable {
		
		long startTime = System.currentTimeMillis();
		
		String returnValue = (String)pjp.proceed();
		
		long endTime = System.currentTimeMillis();
		
		System.out.println(endTime-startTime);
		
		return returnValue;
		
	}
	
	
}

controller가 아니라 서비스에도 걸 수 있음

 

리턴값이 Object인 이유는

 


리턴값이 void인 경우 default return값으로 null을 리턴한다.

 


컨트롤러에서 null을 리턴하면 리퀘스트맵핑url의 jsp로 이동 동작

 

Advice는 return값을 명시하면 null을 리턴

null은 주소자료형으로 int형에 넣을 수 없다.

 


 

'디지털 컨버전스 > Spring' 카테고리의 다른 글

[Spring Framework] WebChat - 익명채팅  (0) 2020.06.12
[Spring Framework] AOP:around - 로그인 체크  (0) 2020.06.12
[Spring Framework] AOP  (0) 2020.06.10
[Spring Framework] Scheduler  (0) 2020.06.10
[Spring Framework] MyBatis  (0) 2020.06.10

OOP : Object Oriented Programming 객체 지향

AOP : Aspect Oriented Programming

- 관점 지향 개발론

- Spring Framework 를 지원하는 기술 (개발의 패러다임으로 보기 어려움)

- 횡단관심사 개발 기술

 

클래스의 기능을 묶는 방식을

 

어드바이저 클래스에 저장

일일히 넣기 어렵고 유리보수 불리

-> AOP

 

weaver 라이브러리 추가

 

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

 


AOP

 

- JoinPoint

   : Advice를 적용할 메서드 후보

   : 사실 상 프로젝트 내의 모든 매서드가 후보가 될 수 있다.

 

- PointCut

   : JoinPoint 중에서 Advice이 적용될 대상으로 선발된 메서드

   : PointCut 표현식에 의해 선발 됨.

 

- Advice

    : pointCut 표현식에 의해 선발된 PointCut 메서드에 적용될 실제 기능

 

- Weaving

   : Advice Metod 를 PointCut 에 적용하는 과정

   : maven 에서 weaver 라이브러리를 적용해야 한다.

 


패키지 생성

Bean태그 추가

Namespace 에서 aop 추가

aop 태그 영역 생성

리턴데이터 타입

 


스프링을 어떻게 설치했고 이클립스 어디서 받았는지 체크

+ Recent posts