React input

종류 : text, range, checkbox 등등

e.target.value : 입력한 값을 가져옴

e.stopPropagation() : 상위 html로 퍼지는 이벤트버블링을 막고 싶을때 사용

splice() : 배열에서 특정 인덱스 삭제

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState([0, 0, 0]);
  let [modal, setModal] = useState(false);
  let [title, setTitle] = useState(1);
  let [입력값, 입력값변경] = useState('');

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>
      <span>{입력값}</span>
      {
        글제목.map(function(a, i){
          return (
            <div className='list'>
              <h4 onClick={() => {setModal(!modal); setTitle(i) }}>{a}, {i} 
              <span onClick={ (e) => {
                  e.stopPropagation();
                  let copy = [...따봉];
                  copy[i] = copy[i] + 1;
                  따봉변경(copy)} }>👍
                </span> {따봉[i]}
                <button onClick={(e) => {
                  e.stopPropagation(); 
                  let copy = [...글제목];
                  copy.splice(i, 1);
                  글제목변경(copy);
                }}>
                삭제</button>
              </h4>
              <p>2월 17일 발행</p>
            </div>
          )
        })
      }

      <input onChange={(e) => { 입력값변경(e.target.value); console.log(입력값) }}></input>
      <button>버튼</button>

      {
        modal == true 
        ? <Modal title= {title} func={() => {let copy = [...글제목]; copy[0] = '여자 코트 추천'; 글제목변경(copy)}} color={'skyblue'} 글제목={글제목}/> 
        : null
      }

    </div>
  );
}

function Modal(props){
  return(
    <div className='modal' style={{background : props.color}}>
      <h4>{props.글제목[props.title]}</h4>
      <p>날짜</p>
      <p>상세내용</p>
      <button onClick={props.func}>글수정</button>
    </div>
  )
}
export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React class (중요 x)

function 대신 class 이용

 

 

 

 

 

 

 

 

 

React 컴포넌트

 

컴포넌트 만드는법 : function을 만듦 - return() 안에 html 담기 - <함수명></함수명>으로 사용

* 함수명은 첫글자 대문자

* 의미없는 <div>대신 <></> 사용 가능

 

* 어떤걸 컴포넌트로 만들면 좋은지 : 반복적인 것, 큰 페이지들, 자주 변경되는 것

* 컴포넌트 단점 : state를 가져다쓸 때 문제가 생긴다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 동적 UI

만드는 방법 : 미리 디자인 완성 - 현재 상태를 state로 저장 - state에따라 어떻게 보일지 작성

* if문 대신 삼항연산자 사용(? : )

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState(0);
  let [modal, setModal] = useState(false);

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>

      <button onClick={ () => { 
        let copy = [...글제목];
        copy[0] = '여자 코트 추천'
        글제목변경(copy) 
      }}>글 수정</button>

      <div className='list'>
        <h4>{글제목[0]} <span onClick={ () => {따봉변경(따봉+1)} }>👍</span> {따봉} </h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4>{글제목[1]}</h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4 onClick={() => {setModal(!modal)}}>{글제목[2]}</h4>
        <p>2월 17일 발행</p>
      </div>

      {
        modal == true ? <Modal/> : null
      }

    </div>
  );
}

function Modal(){
  return(
    <div className='modal'>
      <h4>제목</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 반복문 (map)

array자료형.map(function(a, i){}) : map 자료형

1. array 자료 갯수만큼 함수안의 코드 실행

2. 함수의 파라미터는 array안에 있던 자료 

3. return에 뭐 적으면 array로 담아줌

* a = array자료형의 내용, i = index번호

 

주의 : state내용을 변경하려면, copy로 복사 후, [...변수명]로 화살표(경로) 재지정

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState([0, 0, 0]);
  let [modal, setModal] = useState(false);

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>

      {/* <div className='list'>
        <h4>{글제목[0]} <span onClick={ () => {따봉변경(따봉+1)} }>👍</span> {따봉} </h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4>{글제목[1]}</h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4 onClick={() => {setModal(!modal)}}>{글제목[2]}</h4>
        <p>2월 17일 발행</p>
      </div> */}

      {
        글제목.map(function(a, i){
          return (
            <div className='list'>
              <h4>{a}, {i} <span onClick={ () => {
                  let copy = [...따봉];
                  copy[i] = copy[i] + 1;
                  따봉변경(copy)} }>👍
                </span> {따봉[i]}
              </h4>
              <p>2월 17일 발행</p>
            </div>
          )
        })
      }

    </div>
  );
}

export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React props (state 자식과 부모)

부모가 자식에게만 state 전달 가능(props문법 이용) (자식에서 부모는 전송 불가) 

1. <자식컴포넌트 작명={state이름}>

2. props 파라미터 등록 후, props.작명 이용

* props == 파라미터 문법 (일반 문자도 전송 가능)

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState([0, 0, 0]);
  let [modal, setModal] = useState(false);

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>

      {/* <div className='list'>
        <h4>{글제목[0]} <span onClick={ () => {따봉변경(따봉+1)} }>👍</span> {따봉} </h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4>{글제목[1]}</h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4 onClick={() => {setModal(!modal)}}>{글제목[2]}</h4>
        <p>2월 17일 발행</p>
      </div> */}

      {
        글제목.map(function(a, i){
          return (
            <div className='list'>
              <h4 onClick={() => {setModal(!modal)}}>{a}, {i} <span onClick={ () => {
                  let copy = [...따봉];
                  copy[i] = copy[i] + 1;
                  따봉변경(copy)} }>👍
                </span> {따봉[i]}
              </h4>
              <p>2월 17일 발행</p>
            </div>
          )
        })
      }
      {
        modal == true ? 
          <Modal func={() => {let copy = [...글제목]; copy[0] = '여자 코트 추천'; 글제목변경(copy)}} color={'skyblue'} 글제목={글제목}/> : null
      }

    </div>
  );
}

function Modal(props){
  return(
    <div className='modal' style={{background : props.color}}>
      <h4>{props.글제목[0]}</h4>
      <p>날짜</p>
      <p>상세내용</p>
      <button onClick={props.func}>글수정</button>
    </div>
  )
}
export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React props 활용

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState([0, 0, 0]);
  let [modal, setModal] = useState(false);
  let [title, setTitle] = useState(1);

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>

      {/* <div className='list'>
        <h4>{글제목[0]} <span onClick={ () => {따봉변경(따봉+1)} }>👍</span> {따봉} </h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4>{글제목[1]}</h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4 onClick={() => {setModal(!modal)}}>{글제목[2]}</h4>
        <p>2월 17일 발행</p>
      </div> */}

      {
        글제목.map(function(a, i){
          return (
            <div className='list'>
              <h4 onClick={() => {setModal(!modal); setTitle(i) }}>{a}, {i} <span onClick={ () => {
                  let copy = [...따봉];
                  copy[i] = copy[i] + 1;
                  따봉변경(copy)} }>👍
                </span> {따봉[i]}
              </h4>
              <p>2월 17일 발행</p>
            </div>
          )
        })
      }
      {
        modal == true ? 
          <Modal title= {title} func={() => {let copy = [...글제목]; copy[0] = '여자 코트 추천'; 글제목변경(copy)}} color={'skyblue'} 글제목={글제목}/> : null
      }

    </div>
  );
}

function Modal(props){
  return(
    <div className='modal' style={{background : props.color}}>
      <h4>{props.글제목[props.title]}</h4>
      <p>날짜</p>
      <p>상세내용</p>
      <button onClick={props.func}>글수정</button>
    </div>
  )
}
export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

React 개발환경 세팅

nodejs 검색 - 왼쪽 설치 

vscode 검색 - 설치 

작업할 폴더 생성 - shift 우클릭 - powershell창 열기 

- npx create-react-app 프로젝트명 

* 오류발생시 : 윈도우 검색 - powershell - 우클릭 - 관리자 권한으로 실행 - Set-ExecutionPolicy Unrestricted 입력

vscode - 해당 폴더 열기 

node_modules : 라이브러리 모아놓은 곳

public : static 파일 모아놓은 곳(img)

src : 소스코드 보관함

package.json : 프로젝트 정보

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 실행 

실행 : terminal - new terminal - npm start 

* App.js : 메인 페이지

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 레이아웃 (JSX 문법)

* html 내용은 return () 안에다가 짜야한다

JSX : js파일에서 쓰는 html 대용품

* App.js에서 App.css파일을 가져오려면 className을 설정한 후, 해당 내용을 App.css파일에 작성

import './App.css' 도 해줘야 한다

 

 

중괄호 문법 : 변수명을 중괄호 안에 입력하면, 알아서 값을 가져온다 (거의 모든곳에서 사용 가능)

해당하는 역할을 data binding이라 한다

 

 

 

css를 css파일에서 불러올 수 있지만, 직접 부여할 수도 있다.

style = {{이름 : '값'}} 형식으로 넣어줘야 한다 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React state 

* return ()안에는 하나의 영역(<div>)만 있어야 한다

state : 중요한 자료를 저장하는 변수 문법 (자료를 잠깐 보관)

* let이나 var로 변수를 저장하면 되는데, state를 쓰는 이유는 변수 내용이 변경되었을 때

state는 자동으로 html에 반연되어 재랜더링 해준다

사용법 : let [작명(a), 작명(b)] = useState('내용') : useState는 import 해야한다

{a} : 해당 내용을 불러옴

b : state 변경을 도와주는 함수

 

* Destructuring 문법 : let [a, c] = [1, 2]  //a = 1, b = 2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React state (버튼 및 개수 추가 기능)

* /* eslint-disable */ : 노란색 warning 메시지를 끄는 기능(Lint 끄는 기능)

* onclick 안에는 함수만 가능

* state 변경하는법 : state변경함수(새로운 state)

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React state (array 변경)

* array 데이터는 내용을 저장하지 않고, 경로만 저장

따라서 해당내용을 만드려면 경로(화살표)를 바꿔줘야 한다 

[...변수명] : 해당 변수를 화살표를 벗기고 다시 씌운다.

 

실행 결과

 

 

 

 

 

 

SPRING 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ H2 데이터베이스 설치

https://www.h2database.com/html/main.html - All Platforms 다운 - 압축 풀기 - 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING web socket

 web socket : 양방향 통신 (채팅)

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

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

 

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

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

 

 

socket 관련 class 생성(TestSocket.java)

 

기본 설정 : servlet-context.xml - Namespaces - websocket 체크

 servlet-context.xml - Source -  

<beans:bean id="ts" class="socket 관련 class(TestSocket) 경로" /> : 빈 생성

<websocket:handlers>

<websocket:mapping handler="ts" path="/chat" /> : /chat 을 요청하면 ts객체를 바로보게끔 설정

<websocket:sockjs /> : socket api를 사용할 수 있게 설정

</websocket:handlers>

 

* TestSocket.java - extends TextWebSocketHandler

 

TestSocket.java - Override/Implement Methods - AbstractWebSocketHandler

- after~closed, after~Established, handleTextMessage 체크 - ok

afterConnectionEstablished : 클라이언트가 연동되면 실행

handleTextMessage : 사용자가 메시지를 보내면 실행

afterConnectionClosed : 클라이언트가 종료 및 연결이 끊기면 실행

 

 

해당 test_socket.jsp 페이지에 접속시, 지정한 세션을 부여한다.

"상담사 연결" 버튼을 누르면, chat()함수로 이동한 후, socket이라는 경로의 페이지로 이동한다.

 

 

* controller에서 부여한 session과 TestSocket.java에서 받은 session은 타입이 다르다.

따라서, servlet-context.xml - Source - 

<websocket:handshake-interceptors>
<beans:bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor" />
</websocket:handshake-interceptors>

을 추가한다.

 

 

session.getId() : WebSocketSession에서 부여한 session

session.getAttributes() : controller에서 부여한 session

List에는 session 전체를 넣고, Map에는 key에 session.getId(), value에는 session.getAttributes().get("name")

 

 

TextMessage message로 넘어온 값을 message.getPayload() = 입력한 내용 받아오기

sessionMap.get(session.getId()) : Map에 session.getId()를 통해 밸류가 얻어오기(ex. 홍길동1)

sessionList의 forEach문을 통해, .sendMessage(text)를 통해 문자 전달하기

 

 

연결이 끊겼을 때, 알려주는 역할

 

 

let sock = null : WebSocket 객체를 저장한 변수 sock 선언

let wsUri : "ws://localhost:8080/root/chat/websocket" : 연결이 설정될 WebSocket URI 지정

sock = new WebSocket(wsUri) : 지정된 uri로 새 WebSocket연결을 생성

sock.onmessage = onMessage : 들어오는 메시지를 처리하는 함수 onMessage를 설정

sock.onclose = onClose : 연결이 닫힐 때 처리하는 함수 onClose를 설정

$("#send_msg").keydown( (key) => {
if (key.keyCode == 13) {} }) : 엔터키를 눌렀을때 함수 실행

sock.send() : 추출한 메시지를 서버로 전송

.append() : 요소 끝에 계속 추가하는 역할

 

실행 결과

 

 

 

 

 

 

 

 

SPRING email 전송

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

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

 

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

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

 

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

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

 

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

 

config관련 mail클래스 생성 - 

 

mailController 생성 - 

 

mail Service 생성 - 

 

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

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

 

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

 

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

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING email 인증

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

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

import java.io.PrintWriter;

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

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

import com.care.root.service.MailServiceImpl;

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

import java.util.Random;

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

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

@Service
public class MailServiceImpl {

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

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING scheduler

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

scheduler 관련  config  클래스 생성

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

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING ajax (데이터 주고 받기)

ajax를 사용 안할 때

 

ajax를 사용 할 때

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

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

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING data 전송 방식(json)

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

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

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

보내는 방식(type) : contentType

받는 방식(type) : dataType

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

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

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

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

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

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING RestController

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

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

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

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

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

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

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING SPA

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

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

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

import java.util.ArrayList;

import org.springframework.stereotype.Component;

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

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

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

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

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING SPA 활용

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

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

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

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

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

import oracle.jdbc.proxy.annotation.Post;

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

 

실행 결과

 

 

 

 

 

 

 

SPRING 자동 로그인 (Interceptor & cookie)

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

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

 

구조 

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

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

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

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

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

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

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

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

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

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

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

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

package com.care.root.member.controller;

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

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

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

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

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

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

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

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

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

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING  보안처리 (crosssitescripting XSS)

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

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

 

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

첫번째 방법

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

 

 

두번째 방법

써있는대로 저장

 

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

 

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

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING file upload & download

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

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

 

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

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

 

 bean 추가하는 두가지 방법

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

 

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

 

 

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

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

 

file을 받아오는 두가지 방법

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

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

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

 

 

파일에 저장

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

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

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

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

 

 

db에 파일 저장 

 

화면에 띄우기 및 다운로드

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

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

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

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

 

 

파일 삭제

+ Recent posts