※ 공변과 불공변
=> 공변(covariant) : A가 B의 하위 타입일 때, T<A>가 T<B>의 하위 타입이면 T는 공변
=> 불공변(invariant) : A가 B의 하위 타입일 때, T<A>가 T<B>의 하위 타입이 아니면 T는 불공변

 

※ 제네릭이 만들어진 이유
=> 제네릭 사용이전 collection 사용(타입이 정의되지 않은) 
=> 컬렉션 속의 요소들의 타입이 정의되지 않음 
=> 타입이 보장되지 않아 메소드 사용시 오류 발생
=> 타입을 지정하여 컴파일 시점에 안정성을 보장받는 방법 고안(제네릭)

 

※ 문제발생
=> 제네릭은 불공변
=> 모든 타입에서 공통적으로 사용되는 메소드를 만들 방법이 없음
=> 제네릭 사용전보다 실용성이 떨어져서 와일드카드라는 타입 추가

 

※ 와일드카드
=> 모든 타입을 대신할 수 있는 와일드카드 타입 (<?>) 추가
=> 정해지지 않은 unknown type이기 때문에 Collection<?>로 선언함으로써 모든 타입에 대해 호출이 가능해짐
=> any type이 아니라 unknown type이라서 문제가 발생
=> Collection의 메소드 등을 사용할 때 값을 추가하기 위해서 제네릭 타입인 E 또는 E의 자식을 넣어줘야하지만 unknown 타입이라 컴파일 에러 발생

 

※ 위의 문제를 해결하기 위해 한정적 와일드 카드를 사용
=> 특정 타입을 기준으로 상한 범위와 하한 범위를 지정함
=> 상한 경계 와일드카드(Upper Bounded Wildcard)와 하한 경계 와일드카드(Lower Bounded Wildcard)가 존재

 

class MyGrandParent {

}

class MyParent extends MyGrandParent {

}

class MyChild extends MyParent {

}

 

※ 상한 경계 와일드카드(Upper Bounded Wildcard)
=> extends를 사용해서 와일드카드 타입의 최상위 타입을 정의
=> 상한 경계를 설정
=> <? extends MyParent>으로 가능한 타입은 MyParent와 미지(unknown)의 모든 MyParent 자식 클래스들
=> MyChild와 AnotherChild (또는 그 외의 타입)
=> 컬렉션 c에서 꺼내서 만들어지는 객체(produce)가 반드시 MyChild 타입이 아닌 AnotherChild가 될 수도 있음, MyChild 타입으로 꺼내려고 시도하면 컴파일 에러 발생
=> MyParent 임은 확실하므로 MyParent와 그 부모 타입으로 꺼내는 것은 문제가 없음
=> 갖고 있는 원소를 사용 또는 소모(consume)하여 컬렉션에 추가하는 경우에는 상황이 달라짐
=> 하위 addElement의 경우 모든 타입에 대해 컴파일 에러가 발생

void printCollection(Collection<? extends MyParent> c) {
    // 컴파일 에러
    for (MyChild e : c) {
        System.out.println(e);
    }

    for (MyParent e : c) {
        System.out.println(e);
    }

    for (MyGrandParent e : c) {
        System.out.println(e);
    }

    for (Object e : c) {
        System.out.println(e);
    }
}

void addElement(Collection<? extends MyParent> c) {
    c.add(new MyChild());        // 불가능(컴파일 에러)
    c.add(new MyParent());       // 불가능(컴파일 에러)
    c.add(new MyGrandParent());  // 불가능(컴파일 에러)
    c.add(new Object());         // 불가능(컴파일 에러)
}

 

※ 하한 경계 와일드카드 (Lower Bounded Wildcard)
=> super를 사용해 와일드카드의 최하위 타입을 정의함
=> 하한 경계를 설정
=> <? super MyParent>으로 가능한 타입은 MyParent와 미지의 MyParent 부모 타입들

void addElement(Collection<? super MyParent> c) {
    c.add(new MyChild());
    c.add(new MyParent());
    c.add(new MyGrandParent());  // 불가능(컴파일 에러)
    c.add(new Object());         // 불가능(컴파일 에러)
}

void printCollection(Collection<? super MyParent> c) {
    // 불가능(컴파일 에러)
    for (MyChild e : c) {
        System.out.println(e);
    }

    // 불가능(컴파일 에러)
    for (MyParent e : c) {
        System.out.println(e);
    }

    // 불가능(컴파일 에러)
    for (MyGrandParent e : c) {
        System.out.println(e);
    }

    for (Object e : c) {
        System.out.println(e);
    }
}

 

※ PECS(Producer-Extends, Consumer-Super) 공식
=> 컬렉션으로부터 와일드카드 타입의 객체를 생성 및 만들면(produce) extends 사용
=> 갖고 있는 객체를 컬렉션에 사용 또는 소비(consumer)하면 super를 사용
=> printCollection : 컬렉션으로부터 원소들을 꺼내면서 와일드카드 타입 객체를 생성(produce)
=> addElement : 컬렉션에 해당 타입의 원소를 추가함으로써 객체를 사용(consume)

void printCollection(Collection<? extends MyParent> c) {
    for (MyParent e : c) {
        System.out.println(e);
    }
}

void addElement(Collection<? super MyParent> c) {
    c.add(new MyParent());
}

 

 

출처:https://mangkyu.tistory.com/241

JavaSciprt의 모듈화

- jQuery는 막강한 기능과 다양한 플러그인을 통해서 많은 프로젝트에서 기본으로 사용
- Ajax를 이용하는 경우에는 jQuery의 함수를 이용해서 너무나 쉽게 처리할 수 있기 때문에 많이 사용
- 화면 내에서 JavaScript 처리를 하다 보면 어느 순간 이벤트처리와 DOM 처리, Ajax 처리 등이 마구 섞여서 유지보수 하기 힘든 코드를 만드는 경우가 많음, 이런 경우를 대비해서 좀 더 JavaScript를 하나의 모듈처럼 구성하는 방식을 이용하는 것이 좋음

- JavaScript에서 가장 많이 사용하는 패턴 중 하나는 모듈 패턴
- 관련 있는 함수들을 하나의 모듈처럼 묶음으로 구성하는 것을 의미
- JavaScript의 클로저를 이용하는 가장 대표적인 방법


// 모듈 패턴
- jsModule.js
console.log("JS Module..........")

var runfunction = (function() {
 reutrn { test:"TEST"};
}) ();

- Java의 클래스처럼 JavaScript를 이용해서 메서드를 가지는 객체를 구성
- 모듈 패턴은 JavaScript의 즉시 실행함수와 '{}'를 이용해서 객체를 구성
- JavaSciprt의 즉시 실행함수는 () 안에 함수를 선언하고 바깥쪽에서 실행해 버림
- 함수의 실행 결과가 바깥쪽에 선언된 변수에 할당
- runfunction이라는 변수에 test이라는 속성에 'TEST'라는 속성값을 가진 객체가 할당

// 실행 jsp
- test.jsp
<script type="text/javascript" src="/resources/js/jsModule.js"></script>
<script type="text/javascript">
 $(document).ready(function() {
  console.log(runfunction);
 });
</script>

console.log("Reply Module.....");

// jsp에서 호출해서 사용할 객체
var replyService = (function() {
	// JavaScript에서는 함수의 파라미터 개수를 일치시킬 필요가 없음(callback, error 등 필요에 따라 작성)
	function add(reply, callback, error) { 
    	console.log("add reply");
    
        $.ajax({
            type : 'POST',	// 전송 방식('GET' OR 'POST')
            url : '/replies/new',	// 요청할 URL(컨트롤러 단에서 호출할 주소)
            data : JSON.stringify(reply),	// 서버에 전송할 데이터
            contentType : "application/json; charset=utf-8", // 서버에 전송할 타입(JSON/utf-8)
            success : function(result, status, xhr) { // 요청 및 응답에 성공했을 때 실행할 함수
                if(callback) {
                    callback(result);
                }
            },
            error : function(xhr, status, er) { // 요청 및 응답에 실패했을 때 실행할 함수
                if(error) {
                    error(er);
                }
            }
        })
	}
    
    return {
    	add : add
    };
})();

 

 

JSON.stringify(value, replacer, space) 메서드

- JavaScript 값이나 객체를 JSON 텍스트로 바꾸고 해당 JSON 텍스트를 문자열에 저장

- 객체/배열에서 JSON 문자열을 만드는데 사용

- value(필수) : JSON 문자열로 변환할 값

- replacer(선택) : 이 값이 null 이거나 제공되지 않을 경우 객체의 모든 속성이 결과 JSON 문자열에 포함

- space(선택) : 가독성을 위해 출력 JSON 문자열에 공백을 삽입하는데 사용되는 String or Number 객체

 

REST 방식으로 처리할 때 주의해야 하는 점은 브라우저나 외부에서 서버를 호출할 때 데이터의 포맷과 서버에서 보내주는 데이터의 타입을 명확히 설계해야 하는 것
예를 들어 댓글 등록의 경우 브라우저에서는 JSON타입으로 된 댓글 데이터를 전송하고, 서버에서는 댓글의 처리 결과가 정상적으로 되었는지 문자열로 결과를 알려 주도록 함

 

// consumes : 들어오는 데이터 타입 정의
// produces : 반환하는 데이터 타입 정의

@PostMapping(value ="/new", consumes = "application/json", produces = { MediaType.TEXT_PLAIN_VALUE })
public ResponseEntity<String> create(@RequestBody ReplyVO vo) {

	log.info("ReplyVO : " + vo);
	int insertCount = service.register(vo);
	log.info(Reply INSERT COUNT : " + insertcount);
	
	return insertCount == 1 ? new ResponseEntity<>("success", HttpStatus.OK) : new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}

 

- @PostMapping으로 POST 방식으로만 동작하도록 설계하고, consumes와 produces를 이용해서 JSON 방식의 데이터만 처리하도록 하고, 문자열을 반환하도록 설계
- 파라미터는 @RequestBody를 적용해서 JSON 데이터를 ReplyVO 타입으로 변환하도록 지정
- 댓글이 추가된 숫자를 확인해서 브라우저에서 '200 OK' or '500 Internal Server Error'를 반환하도록 함

<trim>은 주로 단독으로 사용되지 않고 <if>, <choose>와 같은 태그들을 내포해 SQL들을 연결해 주고, 앞 뒤에 필요한 구문들(AND, OR, WHERE 등)을 추가하거나 생략하는 역할을 함

 

예를 들어 검색 조건에서

'WHERE RN <= 50' 은 문제가 없지만

저 조건에다가 writer='user'인 조건이 붙는 다면

WHERE RN <= 50 AND writer='user'

검색 조건에 따라 AND가 붙던지 없던지 바뀌게 됨

 

주로 쓰이는 3가지 속성

- prefix : 문장 앞에 붙임

- suffix : 문장 뒤에 붙임

- prefixOverrides : 해당 문자열이 가장 앞에 올 경우 해당 문자열을 지움

- suffixOverrides : 해당 문자열이 가장 뒤에 올 경우 해당 문자열을 지움

 

- prefix suffix 사용

WHERE
<trim prifix="(" suffix=) AND">
	WHERE RN <= 50
</trim>
writer = 'user'

// 결과 SQL
where (rn <= 50) AND writer = 'user'

 

Context 경로 설정

- tomcat이 설치된 폴더에서 /conf 이동

- server.xml 편집

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
            
            <Context docBase="경로" path="/" reloadable="true" />

            
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>

 

- 해당 파일 밑의 <Host>부분에 <Context> 추가

- 위 <Context> 해석

 '0.0.0.0:8080/경로/list/index' 였던 것을  '0.0.0.0:8080/list/index'를 url에 칠 경우 같은 결과 값을 줌

 즉 '/경로'를 '/'로 바꾼다는 뜻

'프로그래밍 > server' 카테고리의 다른 글

echo_server  (0) 2019.05.15
inet_addr  (0) 2019.05.08

준비물

- 기존에 설치했던 putty

- FileZilla

https://filezilla-project.org/

 

FileZilla - The free FTP solution

Overview Welcome to the homepage of FileZilla®, the free FTP solution. The FileZilla Client not only supports FTP, but also FTP over TLS (FTPS) and SFTP. It is open source software distributed free of charge under the terms of the GNU General Public Licen

filezilla-project.org

 

WAR 파일 추출

- 기존에 진행했던 프로젝트 IDE에서 해당 프로젝트 export -> war파일 추출

 

 

FileZilla 접속 셋팅

- 편집 -> 설정 -> 연결/FTP의 SFTP -> 키 파일 추가 -> 보안키 등록 -> 확인

- New site -> 프로토클 SFTP로 변경 -> 호스트에 instance IP 넣기 -> 포트는 빈칸 -> 사용자(ubuntu) -> 비밀번호 입    력 -> 연결

 

- 리모트에 '/var/lib/tomcat9' 써서 Enter로 이동해도 되고 GUI방식으로 이동해도 됨

- 들어왔으면 webapps에 진입, ROOT 폴더 하나 확인

 

- putty에서 해당 경로에 권한 설정

- war 파일을 wepapps에 끌어 넣고 기다리기

- 이후 몇 분 기다린 후 새로고침시 해당 폴더에 war파일 이름의 폴더 생성

- 전자지갑 압축 푼 것을 FileZilla를 이용해 원하는 위치에 이동(나의 경우 '/var/tools')

- 본인 프로젝트의 DB경로 중 wallet 경로 설정

- 이후 putty에서 톰캣 서버를 껐다 킴

- sudo service tomcat9 stop

- sudo service tomcat9 start

 

본인 프로젝트에 들어가려면

[InstanceIP]:8080/[war 파일 이름]/로컬에서 돌리던 경로

※ 로컬에서 돌리다가 war 파일로 배포시 경로에 프로젝트 명이 추가 됨, 따라서 404 걸리거나 css등이 깨질 수 있음

 

경로에서 프로젝트 파일명 빼기(tomcat 경로 설정)

- FileZilla에서 '/var/lib/tomcat9' 경로에 conf 폴더로 진입

- '/etc/tomcat9'로 이동 됨

- 'server.xml'를 보기/편집 선택(만약 권한이 걸리면 putty에서 'sudo chmod -R 777 /etc/tomcat' 실행)

<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>

맨 밑에서 보면 <Host> 부분에

<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

	<Context docBase="[war 파일명]" path="/" reloadable="true" />

- 해당 <Context> 추가

 ex) 0.0.0.0/8080/war/index로 진입하던 url를

      0.0.0.0/8080/index로 입력해도 0.0.0.0/8080/war/index로 들어가게 경로 설정

주로 페이지의 회원가입이나 아니면 꼭 받아야 하는 필수 항목의 경우

request.getParameter로 값을 받아 처리함

그러나 request.getParameter(parameter) != null

필수 항목이기에 null값을 조건부에 추가 했으나 조건부에 안 걸리고 그냥 통과해버리는 현상 발견

그래서 넘겨진 값을 확인하니 "" 빈칸으로 넘어옴

null과 ""는 차이가 있음

null은 선언만하고 아직 메모리에 할당하지 않은 것이라면

""의 경우 이미 메모리에 할당되어 사용 중인 상태의 차이

따라서 조건부에

request.getParameter("parameter") != null && request.getParameter("parameter") != ""

두 가지 경우를 추가

어이없는 실수였지만 몇십 분 걸림

DB 생성

앞서 톰캣 서버 실행까지 된 후 DB를 만듦

다시 오라클 클라우드 관리 페이지에 들어가서 Create an ATP database 클릭

 

 

- Display name : 오라클 클라우드 관리 화면에서 보일 이름

- Database name : 실제로 사용할 DB 이름(프로젝트에 사용되니 간편하면서도 구분 가능하게 짓는 걸 추천)

 

- Always Free : 과금으로 안 넘어가고 무료 범위 내에서 사용하기 위해 옵션 버튼 활성화

- 오라클 DB 19c 버전 사용(default 값 그대로)

 

- Username : ADMIN 고정이라 손댈 수가 없고 그대로 사용

- Password : 말 그대로 실제로 사용할 DB Password로 대문자, 소문자, 숫자를 최소 하나씩 포함해야 하며 12~30자 사이로 만들어야 함(잊지 않게 메모 추천)

 

- 그 이후 딱히 손댈 것은 없이 밑에 create 버튼으로 생성 후 5분 정도 기다리면 초록색 AVAILABLE로 바뀌면서 사용 가능

- DB Connection 버튼 클릭

 

- 전자 지갑을 위해서 Download wallet 버튼을 눌러 저장 후 잘 관리해야 함(DB 연결 시 필요)

 

만들어진 DB 테스트

https://www.oracle.com/tools/downloads/sqldev-downloads.html

- 페이지에 들어가서 본인의 컴퓨터 환경에 맞게 다운로드 및 설치 진행

 

- 실행 후 왼쪽 상단에 초록색 + 버튼을 클릭

 

- 사용자 이름 : admin(따로 수정 불가능하므로 고정)

- 비밀번호 : DB 생성 시에 설정한 Password 입력

- 접속 유형 : 클라우드 전자 지갑으로 변경

- 전자지갑 추가 : 찾아보기를 눌러 아까 Download wallet 받은 파일 추가 시 설정한 DB이름 뒤 _high 확인

 

위의 칸들 다 처리 후 추가했을 때 정상적으로 추가돼서 실행하는지 확인 작업

 

실제 프로젝트와 연동

 

해당 환경은 Spring Framework 환경의 sts툴을 사용할 때 기준

junit을 사용해 테스트하였음

클래스 하나 생성 후 위의 내용을 그대로 작성하고

url : jdbc:oracle:thin:@[dbname]_high?TNS_ADMIN=[wallet 경로]

id : admin

pw : DB Password

수정

url의 경우 다운로드한 wallet을 압축 풀고 그 압출 푼 경로를 넣으면 됨

※ 주의 사항

- 되도록이면 경로에 한글이 없는 편이 좋고 루트 경로에 가까울수록 좋음

- 윈도우 환경에서 복사 붙여 넣기를 한다면 경로가 역슬래쉬로 붙여 넣기 되므로 슬래쉬로 바꿔야 함

 

이 외에 문제가 생긴다면 공식 페이지 확인

https://docs.oracle.com/en/cloud/paas/autonomous-database/adbsa/connect-jdbc-thin-wallet.html#GUID-20656D84-4D79-4EE9-B55F-333053948966

 

Using Oracle Autonomous Database on Shared Exadata Infrastructure

Autonomous Database mandates a secure connection that uses Transport Layer Security (TLSv1.2). Depending on the configuration options, Autonomous Database supports mTLS and TLS authentication. This section covers using JDBC Thin Connections with a wallet (

docs.oracle.com

DataSourceSample.java or UCPSample.java from JDBC code samples 등 샘플 테스트 코드 지원

 

실행전 공식 홈페이지 문서를 읽다 보면 보이는 

- oraclepki.jar

- osdt.jar

- osdt_cert.jar

위 세가지를 추가하라고 함

해당 다운로드 링크에서 다운로드해서 직접 프로젝트에 주입시키던지, Maven 디펜던시를 추가하는 방법 두 가지가 있음

https://www.oracle.com/database/technologies/appdev/jdbc-ucp-183-downloads.html

 

또는 Maven을 이용할 경우 https://mvnrepository.com/

해당 홈페이지에서 해당되는 jar파일 명 검색 후 3가지 파일을 디펜던시에 추가

※ 3개의 버전을 통일 시켜야 함

 

이후 junit Test 진행

여기까지 문제없이 실행된다면 실제 프로젝트의 DB 관련 config의 url, id, pw를 넣으면 됨

오라클 클라우드를 선택하게 된 이유

게시판 사이트 프로젝트를 진행한 환경은 Java, Oracle로 진행을 했고 그 이후 호스팅을 위해 서버를 알아보게 됨

그중 많이 사용하는 것이 AWS, 카페24 두 가지가 있었고, AWS의 경우 과금 자동 제한 등 서비스가 없어서 만약 이 서버를 계속 돌리거나 혹은 잊어버렸을 경우 채굴 등에 끌려가던지 위험이 있을 수 있고 그런 사례들도 어렵지 않게 찾아볼 수 있었음 그래서 AWS는 제외

두 번째로 카페24의 경우 오라클 DB를 MariaDB로 마이그레이션 해야 하는 문제가 발생해서 제외

그중 클라우드 시장에 늦게 뛰어들게 된 오라클에서 클라우드 서비스를 운영 중이었으며 혜택?이라고 해야 하나 차이가 타사에 비해 공격적으로 나와서 커서 나에게 딱 맞는 조건

물론 장점만 있지는 않고 큰 단점이 있음

다른 서비스들에 비해 정보가 부족해 오류가 떴을 경우 하나하나 찾아서 해결 해야함

- 나쁘지 않은 무료로 제공하는 사양

- 과금 제한

- DB 오라클 강제(어차피 프로젝트를 오라클로 진행해서 오히려 진행하기 편함)

- 다른 클라우드 서비스에 비해 턱없이 부족한 정보(유일한 단점)

 

오라클 클라우드 가입 및 인스턴스 생성

먼저 오라클 페이지에 가서 무료로 시작하기를 클릭 후 서비스 가입을 한다.

https://www.oracle.com/kr/cloud/free/

 

 

그 이후 로그인한 후 화면에서 Create a VM instance를 클릭해 가상 머신 서버를 만듦

 

 

Name 부분은 말 그대로 보일 이름으로 무료의 경우 2개의 서버를 만들 수 있으며 만든 후에 Name은 변경이 가능

Placement는 말 그대로 서버의 위치로 오라클의 경우 한국에도 서버를 두고 있기에 만약 한국에서 사용한다면 당연히 서울로 지정하는 것이 속도와 안정성 면에서 좋을 것, 아마 가입 시에 지역을 한국에 해놨다면 자동으로 되어 있을 것

그 후 수정해야 할 것이 Image and shape 부분

 

개인에 맞는 것을 지정하면 되고 나의 경우 우분투 서버로 설정

image 말고 shape의 경우 기본으로 되어있는 무료 사양으로 진행

 

 

그 후 제일 중요하다고 볼 수 있는 key 저장

기존에 가지고 있던 것이 아니라 로컬로 진행했던 프로젝트를 호스팅 하기 위해 새로 서버를 만드는 중이라면

Generate a key pair for me 부분에서

Save Private Key 부분을 눌러 저장

만약 개인 프로젝트 및 한대의 컴퓨터가 아니라 여러 컴퓨터 여러 명이 진행할 경우는 방법이 달라짐

- 다른 접근이 필요할 경우 putty를 이용

- putty 다운로드 링크

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

 

Download PuTTY: latest release (0.76)

This page contains download links for the latest released version of PuTTY. Currently this is 0.76, released on 2021-07-17. When new releases come out, this page will update to contain the latest, so this is a good page to bookmark or link to. Alternativel

www.chiark.greenend.org.uk

 

본인의 운영체제에 맞게 진행하면 되는데 보통 윈도우 64bit를 사용 중이라면 위의 표시한 것으로 진행하면 됨

 

설치가 완료됐다면 바탕화면에서 윈도우키를 누르고 putty를 검색한 후에 파일 위치 열기를 클릭 후 PuTTYgen 실행

 

위 목록에서 key 부분에 SSH-2 RSA key 체크되어있는지 확인 후 Generate 클릭

 

progress bar가 올라가기 시작 마우스를 움직이면 더 빠르게 올라감(마우스 움직임으로 암호화 값을 만드는 방식)

완료되었다면 Save private key 버튼을 눌러 원하는 위치에 저장하고

2번째 upload로 하고 만들어진 키를 추가하거나 3번째 키 복사 붙여 넣기에 위 사진의 빨간 부분 전체 복사해서 붙여 넣으면 됨

위에 것이 없으면 서버에 접근할 수 없으므로 잊어먹지 않도록 주의

이후 딱히 손댈 것 없이 마지막의 create 버튼을 눌러 생성

 

이후 만들어지면 현재 화면

아마 왼쪽에 RUNNING이 아니라 노란색이면 만들어지는 중이라 약간의 시간(5분 정도) 기다리면 해당 화면으로 바뀜

여기서 중요한 것은 Public IP address 부분이다.

일단 만들어졌다면 해당 서버에 접근해야 하는데 여기에는 putty를 이용한다

 

 

putty를 실행 후 Host Name에 아까 만들었던 인스턴스의 ip를 copy paste를 후

 

왼쪽 Connection - SSH - Auth에 Browse... 버튼을 눌러 아까 만든 키를 넣고

다시 session으로 돌아와 open 버튼 클릭

 

정상적으로 실행되었다면 나의 경우 아까 ubuntu로 만들었기 때문에 'ubuntu' 입력 후 아까 키를 만들 때 설정한 pw를 입력하면 정상적으로 로그인이 됨

 

서버에 JDK 및 tomcat9 설치

- sudo apt update // 업데이트 리스트를 불러옴

- sudo apt upgrade // 실제 업데이트 적용

(프로젝트의 Java 버전에 맞게 설치)

- sudo apt install default-jdk // 기본 jdk 설치 (우분투 20.04의 경우 JDK11)

- sudo apt-get install openjdk-8-jdk // java 1.8버전으로 설치(JDK8)

- sudo apt install tomcat9 // tomcat9 설치

- sudo systemctl status tomcat9 // tomcat이 정상 설치되고 돌아가는지 확인(초록색으로 'active (running)' 확인)

 

(iptables로 설정해도 되나 ufw 툴을 사용하는게 더 편한듯?)

- sudo apt install ufw // 방화벽 설정 툴

- sudo ufw allow 8080/tcp // 8080포트 방화벽 해제

- sudo ufw allow 80/tcp // 80포트 방화벽 해제

 

이후 다시 오라클 클라우드 인스턴스에 가서 방화벽 설정을 해야 함

Primary VNIC 부분의 Subnet 클릭

들어가서 Security Lists의 목록에 있는 것 클릭 후

 

Ingress Rules의 Add Ingress Rules 버튼 클릭

 

Source CIDR에 0.0.0.0/0 입력

port는 설정 안 해도 되고 설정한다면 80,443,432 포트 입력(공백 없이)

각 포트

80 : HTTP

443 : HTTPS

4321 : 개발에 사용되는 포트

 

이상하게 포트 설정했더니 사용하다가 문제 발생해서 그냥

0.0.0.0/0에 모든 Allprotocols로 전부 허용해버림

 

방화벽 설정이 끝났다면 다시 putty로 이동

- sudo apt install net-tools // 포트 확인 툴

- netstat - atn // 포트 확인

- sudo iptables -F // iptables 규칙 초기화

- sudo timedatectl set-timezone Asia/Seoul // 서울로 서버 시간 설정

브라우저에 들어가서 해당 인스턴스 8080 포트로 접속

- [주소]:8080 입력

해당 화면이 뜰 경우 성공

 

 

etc)

잘 사용하다가 어느날 접속하려고 보니 

사이트에 연결할 수 없음

응답하는데 시간이 너무 오래 걸림

ERR_CONNECTION_TIMED_OUT 에러가 뜸

 

1. 일단 putty로 instance에 접속이 되는지 확인

2. 해당 포트가 listen 정상 작동 중이라면

3. 오라클 클라우드 방화벽 설정에 들어가서 추가로 설정한 것 다 지우고 0.0.0.0/0에 Allprotocals 추가

4. putty에서 sudo iptables -F

 방화벽 관련 설정 날려봄

5. 위에 해도 안되면 8080포트를 변경 후 다시 시도

Controller의 특징

  • HttpServletRequest, HttpServletResponse를 거의 사용할 필요 없이 필요한 기능 구현
  • 다양한 타입의 파라미터 처리, 다양한 타입의 리턴 타입 사용 가능
  • GET 방식, POST 방식 등 전송 방식에 대한 처리를 어노테이션으로 처리 가능
  • 상속/인터페이스 방식 대신에 어노테이션만으로도 필요한 설정 가능

 

@RequestMapping의 변화

  • 몇 가지의 속성 추가 가능
  • method 속성을 가장 많이 사용(GET/POST 방식을 구분해서 사용할 때 이용)
  • 스프링 4.3버전부터 @RequestMapping을 줄여서 @GetMapping, @PostMapping으로 사용
@RequestMapping(value = "/basic", method= {RequestMethod.GET, REquestMethod.POST})
public void basicGet() {
    log.info("basic get");
}


// 축약형
@GetMapping("/basicOnlyGet")
public void basicOnlyGet() {
    log.info("basic get only")
}
  • @RequestMapping은 GET, POST 방식 모두를 지원해야 하는 경우에 배열로 처리해서 지정
  • @GetMapping의 경우 오직 GET 방식만 사용할 수 있으므로, 간편하나 기능에 대한 제한이 많은 편

 

데이터 전달자 Model

  • Model 객체는 JSP에 컨트롤러에서 생성된 데이터를 담아서 전달하는 역할을 하는 존재
  • 모델2 방식에서 사용하는 request.setAttribute()와 유사한 역할을 함
// Servlet에서 모델2 방시으로 데이터를 전달하는 방식
request.setAttribute("serverTime", new java.util.Date());
RequestDispatcher = request.getRequestDispathver("url");
dispathcer.forward(request, response);


// 스프링 MVC에서 Model을 이용한 데이터 전달
public String home(Model model) {
    model.addAttribute("serverTime", new java.util.Date());
    return "home";
}
  • 메서드의 파라미터를 Model 타입으로 선언하게 되면 자동으로 스프링 MVC에서 Model 타입의 객체를 만들어 주기 때문에 개발자의 입장에서 필요한 데이터를 담아 주는 작업만으로 모든 작업이 완료
  • Model을 사용해야 하는 경우는 주로 Controller에 전달 된 데이터를 이용해서 추가적인 데이터를 가져와야 하는 상황
  • ex) 리스트 페이지 번호를 파라미터로 전달받고, 실제 데이터를 View로 전달해야 하는 경우
  • ex) 파라미터들에 대한 처리 후 결과를 전달해야 하는 경우

 

@ModelAttribute 어노테이션

  • 강제로 전달받은 파라미터를 Model에 담아서 전달하도록 할 때 필요한 어노테이션
  • 타입에 관계없이 무조건 Model에 담아서 전달되므로, 파라미터로 전달된 데이터를 다시 화면에서 사용해야 할 경우 유용하게 사용
public String noModelAttribute(sampleDTO dto, int page) {
    log.info("dto : " + dto);
    log.info("page : " + page);

    return "home";
}

public String useModelAttribute(sampleDTO dto, @ModelAttribute("page") int page) {
    log.info("dto : " + dto);
    log.info("page : " + page);

    return "home";
}

 

RedirectAttibutes

  • model 타입과 더블어서 스프링 MVC가 자동으로 전달해 주는 타입
  • 조금 특별하게 일회성으로 데이터를 전달하는 용도로 사용
  • 기존 servlet에서는 response.sendRedirect()를 사용할 때와 동일한 용도로 사용
// servlet에서 redirect 방식
response.sendRedirect("/home?name=temp");


// 스프링 MVC를 이용하는 redirect 처리
rttr.addFlashAttribute("name", "temp");
return "redirect:/";

 

Controller의 리턴 타입

  • 어노테이션을 사용하는 방식으로 변한 이후에 가장 큰 변화 중 하나 리턴 타입이 자유로워 짐
  • String : jsp를 이용하는 경우에는 jsp 파일의 경로와 파일이름을 나타내기 위해서 사용
  • void : 호출하는 URL과 동일한 이름의 jsp를 의미
  • VO, DTO : 주로 JSON 타입의 데이터를 만들어서 변환하는 용도로 사용
  • ResponseEntity : response 할 때 http 헤더 정보와 내용을 가공하는 용도로 사용
  • Model, ModelAndView : Model로 데이터를 변환하거나 화면까지 같이 지정하는 경우에 사용
  • HttpHeaders : 응답에 내용 없이 Http 헤더 메서지만 전달하는 용도로 사용

+ Recent posts