2018년 3월 30일 금요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 7일차(JSP, MVC, Redirect, forward)

  • Session
    • 브라우저마다 세션아이디를 생성하고 HttpSession를 생성한다.
  • Http get
    • get방식은 key=value
    • get방식으로 요청하면 주소뒤에 ?name=값 형태로 붙어서 요청한다.
    • 파라미터가 없으면 null이 반환된다.
  • Jsp Ecriptlets
    • 주소 요청이 오면 jsp가 있는지 없는지 검사한다. 
    • HttpJspBase를 상속받는다.
    • jsp 파일이 있다면 .java파일로 변경하고 _jspService()메소드에서 out.write()메소드로 사용자가 작성한 내용을 출력한다.
    • jsp파일에서 out.write()메소드를 사용하여 실행하면 화면에 출력된다. 그 이유는 JSP파일에서 내장객체로 out을 가지고 있기 때문이다.
    • 소스를 보고 싶으면 쉘에서 find / -name index_jsp.java 명령어로 위치를 찾아서 vi 명령어로 본다. 예를들면 다음과 같은 경로에 파일이 있다.(/Users/mac/Library/Caches/IntelliJIdea2017.2/tomcat/Tomcat_8_0_33_FastCampusJavaWebMaster_3/work/Catalina/localhost/ROOT/org/apache/jsp/index_jsp.java)
    • HTML + JAVA 로직이 섞여있어서 개발 후 유지보수 할때 불편한 점이 있다.
    • <%@ 지시문 %>  , <% 자바코드  %>로 사용 가능하다.
    • EL문을 사용할수 있다.
    • taglib는 태그라이브러리를 사용할수 있다. WAS는 태그라이브러리 설정이 있는지 확인한다. classpath에서 taglib에 적혀있는 uri가 있는지 확인한다. 
    • 만약에 jstl taglib를 사용하려면 maven dependency에 'jstl'을 추가하고 jsp에서 taglib jstl 지시문을 설정한다.
  • MVC1
    • JSP <-> CLASS <-> DB 와 같은 구조가 MVC1구조다.
    • 단점은  JSP가 가지고 있는 단점이다.
  • MVC2
    • 서블릿(로직) -> CLASS -> DB 호출후 결과를 JSP에게 넘기고 JSP에서는 JSTL, EL문만 사용해서 개발한다.(Forward방식으로 전달한다.
  • Redirect
    • 1. 브라우저는 서버에 요청을 한다.
      2. Redirect가 되어있으면  Status Code : 302, location: 주소값 을 반환한다.
      3. 브라우저는 302코드 받았으면 자동으로 서버에 location에 적혀있는 주소로 요청한다.
      4. 서버가 응답한다.



  • Forward
    • 포워딩할때는 path가 반드시 '/' 로 시작한다. 
    • 포워딩 대상에 값을 전달하려면 request가 가지고 있는 setAttribute메소드를 이용하면 된다.
    • JSP에서 setAttribue한 값을 출력할수 있다.


  • 실습
    • 서블릿 게시판, 상세 보기, 페이징 처리 만들기

Share:

JAVA 직렬화

  • byte로 변환하여 파일 또는 네트워크를 통해서 Stream(송수신)을 하는것을 말한다.
  • 자바 기본 타입과 java.io.Serializable를 인터페이스를 상속받은 객체는 직렬화 사용이 가능하다. 
    • 변환하는 객채 안에 필드도 직렬화를 구현하고 있어야 직렬화가 가능하다.

Share:

2018년 3월 29일 목요일

Java Stream의 이용 방법

1. Stream에서의 flush() 

Applicaion
JVM
OS(키보드)
의 구조를 가지고 있는데 close, flush라는 함수를 쓰는 이유는 OS 및 Applicaion에 전달하기 위해서다. close() 함수를 호출하면 flush() 함수를 자동으로 실행한다.

2. Stream api이용 방법

사용자가 키보드로 입력한 글자를 한줄씩 읽기위해서는 BufferedReader를 사용하고 싶다고 했을때 stream의 흐름과 사용방법에 대해 알아보자.

사용자가 입력한 값을 한줄씩 읽고 싶다고 할때 BufferedReader를 이용해서 읽을 수 있다.
사용자가 키보드로 입력한 값의 형식은 InputStream 이므로 위의 사이트에서 InputStream 형태로 변수를 받을 수 있는 reader를 찾으면 InputStreamReader이 있다.
그렇다면 InputStream 형태로 입력한 값을 BufferReader의 readLine()를 통해 사용하고싶다면 아래와 같은 구조를 이해하고 사용하면 될것이다.

BufferedReader br = new BufferedReader(new InputStreamReader((System.in)));



흐름을 이해하고 api를 보며 이용하는 습관을 가지자.
Share:

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 6일차(TDD, 쿠키, 세션)

  • TDD
    • mokito 에서 spy
    • 실제로 객체를 생성해서 테스트 할수 있다.
    • argument.capture()는 메소드가 실행했을때의 객체를 복사한다.
    • 회귀테스트 : 소스는 복잡하게 연결되어 있다. 작은 부분이 수정되면 모든기능을 다시 테스트해야한다.
    • Agile + TDD
  • 개발
    • 개발하면서 문제가 있다면 실시간으로 수정해야한다.(나중에 하면 망한다.)
    • 코드는 시간이 흐르면 조금씩 망가진다. 끊임 없이 ODD와 패턴 구문들을 적용해서 리팩토리 해야한다(Test + 리팩토링은 같이 하는 것이다)
    • 소스를 수정하면 기존 Test코드를 실행하여 이상이 없는지 확인하면 이상이 없는것이다.
      개발 <-> 수정(리팩토링<-실시간)
  • Agile
    • 짧은 주기로 개발 ,개발 수정, Test를 반복한다.
  • 마크업
    • HTML : 태그가 정해져있다. 브라우저에서 읽는다. 
    • XML : 확장가능한 마크업 언어이다, 태그가 정해져 있지 않다. 데이터를 표현한다. 최소 1개이상의 요소가 있어야한다.(시작tag+내용+종료tag로구성), 제일 바깥쪽 요소는 Root Element이다.
      • 구조정의 : DTD, XML스키마
  • Web Maven Project
    • HttpServlet은 톰캣이 가지고 있다. 그래서 메이븐 설정에 서블릿을 추가하고 클래스때만 사용하게 설정한다.
    • Servlet 3.0부터는 web.xml말고 JAVA config(ServletContainerInitializer)로 설정이가능하다
      • WAS는 web.xml을 먼저 찾고 classloader 에서 ServletContainerInitializer을 구현한 class를 찾는데 그 시간이 오래걸릴수도 있다.
  • 상태유지
    • 쿠키
      • 1. 브라우저가 서버에 요창할때 브라우저에서 쿠키가 없으면 서버는 쿠키(key=value)를 만들어 보낸다
        2. 브라우저가 같은서버에 재 요청시 쿠키를 자동으로 가지고간다.
      • key와 value는 문자열만 가능하다.
      • 쿠키개수가 제한이 있다
      • 보안문제가 있다.
      • 쿠키는 new를 통해 생성하여 응답한다.
      • 톰캣같은 경우는 jsessionid를 자동으로 만들어서 보낸다.(WAS마다 다르다.)
    • 세션
      • request.getSession을 입력하면 처음이면 sessionId를 만들고 처음이 아니면 기존 sessionId를 이용한다.
      • 브라우저가 보낸 요청데이터를 토대로 세션id를 만든다.(String key = Object value)
      • 새로운 브라우저가 요청할때마다 HttpSession 자료구조를 만든다.
      • 다양한 값이 저장가능하다.(객체도)
      • request한테 정보를 받아서 세션id 여부를 파악하여 첫 요청이면 Httpsession을  통해 쿠키데이터 값을 기반으로 값을 만들어서 쿠키에 넣어서 반환한다.
      • WAS에 따라서 처음 요청시 자동으로 만들어서 보내는경우도 있다.
Share:

알고리즘 이진검색

문제

1. min = 0 이고 max = n-1 입니다.
2.max < min, 이라면 멈춥니다. 타겟이 배열에 존재하지 않습니다. -1을 반환합니다.
3. 'guess'를 'max'와 'min'의 평균으로 계산하고 (정수가 될 수 있도록) 내림합니다.
4. 배열[guess]가 타겟과 같다면 멈춥니다. 찾았습니다! guess를 반환합니다.
5. 만약 추측이 너무 낮았다면, 즉 배열[guess] < 타켓이라면, min = guess + 1로 바꿉니다.
6. 그렇지 않다면 추측이 너무 높습니다. max = guess - 1로 바꿉니다.
7. 2단계로 돌아갑니다.

풀이

var doSearch = function(array, targetValue) {

    var min = 0;

  var max = array.length - 1; // 첫 번째 인덱스는 1이 아니라 0에서 시작합니다.

  var guess;

  var targetValue;

  var count = 0; //count 변수를 0으로 초기화시킵니다.

  while(max >= min){ //max 값이 min보다 커야 반복문이 실행됩니다.

      guess = Math.floor(( max + min )/2); // 받은 인자에 Math.floor 함수를 써서 가운데 인덱스 값의 소수점을 버릴거에요.

      println(guess); // 각 단계의 guess를 출력하게 할래요.

      count++; // 반복문이 실행될 때마다 카운트를 1회씩 증가시킵니다.

      if(array[guess] < targetValue){ // 우리가 추론한 guess 값이 targetValue보다 작을 경우,

          min = guess+1;  //범위를 하나씩 더 늘립니다.

      }

      else if(array[guess]> targetValue){ //우리가 추론한 guess 값이 targetValue보다 클 경우,

          max = guess-1; // 범위를 하나씩 더늘립니다.

      }

      else { //추론한 guess 값이 targetValue와 일치하다면

          println(count); // 마지막 반복문에서 최종 카운트된 횟수를 출력합니다.

      return guess; // guess를 반환합니다.

      }

    }  

    return -1; // 배열에 targetValue가 없을 경우, -1을 반환합니다. 즉 max < min이면 더이상 반복문을 돌리지 않습니다.

};

var primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,

        41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97];


var result = doSearch(primes, 73);

println("Found prime at index " + result);

Program.assertEqual(doSearch(primes, 73), 20);
Program.assertEqual(doSearch(primes, 89), 23); // 다른 수도 검사해볼까요?
Program.assertEqual(doSearch(primes, 13), 5);  // 다른 수도 검사해볼까요?
* reference
Share:

2018년 3월 28일 수요일

Thead사용법과 notify(), notifyAll(), wait() 사용시 주의점

1. Thread 구현 방법

자신이 Runnable 객체를 가지고 있으면 Runnable의 run()메소드를 호출하고 아니면 다른경우의 run()을 호출한다.

1.1. 상속

public class ThreadExam01 {
    public static void main(String[] args) {
        MyThread01 t1 = new MyThread01("*");
        MyThread01 t2 = new MyThread01("-");
        MyThread01 t3 = new MyThread01("|");
        t1.start();
        t2.start();
        t3.start();
        System.out.println("end!!");

    }
}
/*
Thread를 만드는 방법.
1) Thread를 상속받는다.
2) run() 메소드를 오버라이딩 한다.
   run() 메소드안에 동시에 수행하고 싶은 작업(코드)를 작성한다.
3) Thread의 실행은 Thread인스턴스를 생성 후 start()메소드를 사용한다.
*/
class MyThread01 extends Thread{
    private String name;
    public MyThread01(String name){
        this.name = name;
    }

    @Override
    public void run(){
        for(int i=0; i<=10; i++){
            System.out.print(name);
            try{ // 0<= x < 1000
                Thread.sleep((int) (Math.random() * 1000));
            }catch (Exception ex){

            }
        }
    }
}

1.2. 인터페이스

public class ThreadExam02 { //템플릿 메소드 패턴
    public static void main(String[] args) {
        /*
            2) Thread(Runnable) 생성자에 Runnale인터페이스를 구현하고 있는 인스턴스를 파라미터로 전달한다.
        */
        Thread t1 = new Thread(new MyThread02("*"));
        Thread t2 = new Thread(new MyThread02("-"));
        Thread t3 = new Thread(new MyThread02("|"));
        t1.start();
        t2.start();
        t3.start();
        System.out.println("end!!");
    }
}

/*
Thread를 만드는 방법.
1) Runnable 인터페이스를 구현한다.
2) run() 메소드를 구현한다.
   run() 메소드안에 동시에 수행하고 싶은 작업(코드)를 작성한다.
3) Thread의 실행은 Thread인스턴스를 생성 후 start()메소드를 사용한다.
*/
class MyThread02 implements Runnable {
    private String name;
    public MyThread02(String name){
        this.name = name;
    }

    @Override
    public void run(){
        for(int i=0; i<=10; i++){
            System.out.print(name);
            try{ // 0<= x < 1000
                Thread.sleep((int) (Math.random() * 1000));
            }catch (Exception ex){

            }
        }
    }
}

2. 동기화(synchronized)

하나의 객채에서 멀티스레드 환경일때 하나의 스레드만 사용할수 있게 동기화 처리하는것이다.
하나의 클래스에 synchronized 가 3개의 메소드가 있고 2개의 메소드에만 synchronized가 적용되어있다고 하면 synchronized가 있는 메소드들만 동기화 처리되고 하나의 메소드는 스레드가 공유하여 실행된다.
synchronized가 처리된 메소드들은 하나의 묶음으로 되어있다고 생각하며 좋을거 같다. 스레드가 synchronized가 처리된 메소드중에서 하나를 호출하면 그 쓰레드는 Lock을 획득하고 다른 synchronized 처리가 된 메소드는 대기하게 된다.

package examples;


public class ThreadExam04 {
    public static void main(String[] args) {
        Exam exam = new Exam();
        MyThread04 t1 = new MyThread04(exam, 1);
        MyThread04 t2 = new MyThread04(exam, 2);
        MyThread04 t3 = new MyThread04(exam, 3);

        t1.start();
        t2.start();
        t3.start();
    }


}

class Exam{

    public void a() {
        for(int i=0; i<10; i++){
            System.out.print("a");
            try{ // 0<= x < 1000
                Thread.sleep((int) (Math.random() * 1000));
            }catch (Exception ex){

            }
        }
    }

    public synchronized void b() {
        for(int i=0; i<10; i++){
            System.out.print("b");
            try{ // 0<= x < 1000
                Thread.sleep((int) (Math.random() * 1000));
            }catch (Exception ex){

            }
        }
    }

    public synchronized void c() {
        for(int i=0; i<10; i++){
            System.out.print("c");
            try{ // 0<= x < 1000
                Thread.sleep((int) (Math.random() * 1000));
            }catch (Exception ex){

            }
        }
    }
}

class MyThread04 extends Thread{
    private Exam exam;
    private int num;
    public MyThread04(Exam exam, int num){
        this.exam = exam;
        this.num = num;
    }

    @Override
    public void run(){
        if(num == 1){
            exam.a();
        }else if(num == 2){
            exam.b();
        }else if(num == 3){
            exam.c();
        }

    }


}

2.1 wait(), notify() ,notifyAll() 함수

Lock을 가지고 있는 쓰레드가 실행중 wait() 함수를 호출하면 현재 가지고 있는 Lock을 반환하고 대기 상태로 빠지며 다른 쓰레드가 notifyAll() 함수를 호출하면 대기 상태에 있는 쓰레드를 깨운다. 대기 상태에 있던 다수의 쓰레드가 깨어나면서 다시 경쟁을 하며  하나의 쓰레드가 Lock을 획득한다.
notify()라는 함수는 하나의 쓰레드를 깨우는 것인데 대기 상태에 들어간 순서대로 깨우는것이 아니니 사용시 주의해야한다.
wait(), notifyAll() 함수를 사용할때 실수할 수 있는 경우를 알아보자.

public class ThreadBank{
    /*
  *  withdraw 함수와 deposit 함수를  synchronized 키워드를 사용 하였다.
  *  한 쓰레드가 withdraw 함수를 실행하는 동안 다른 쓰레드가 deposit 함수를 호출하거나
  *  withdraw 함수를 호출할 수 없다.
  */

    private int money = 0;

    ThreadBank(int money) {
        this.money = money;
    }

    synchronized void withdraw(int value) {

        try {
            // if 문을 사용하여 현재 money 가 0 인지 확인한다.
            if(money == 0)
                wait(); // money 가 0이면 Lock 을 릴리즈하고 대기 상태에 빠진다.

            money -= value;

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Withdraw. money : " + money);

    }

    synchronized void deposit(int value) {
        money += value;

        // wait 을 호출하여 대기 상태에 빠져 있는 모든 쓰레드들을 깨운다.
        notifyAll();

        System.out.println("Deposit. money : " + money);
    }
}

class Producer implements Runnable {

    private ThreadBank mBalance;

    Producer(ThreadBank balance) {
        mBalance = balance;
    }

    @Override
    public void run() {

        // 100번 루프를 돌면서 100씩 저금한다.
        for(int i=0; i<100; i++) {
            mBalance.deposit(100);
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

class Consumer implements Runnable {

    private ThreadBank mBalance;

    public Consumer(ThreadBank balance) {
        mBalance = balance;
    }

    @Override
    public void run() {

        while(true) {
            // 무한 루프를 돌면서 10씩 인출한다.
            mBalance.withdraw(10);

        }
    }
}

class Main {

    public static void main(String[] args) {

        ThreadBank bank = new ThreadBank(0);

        Producer producer = new Producer(bank);
        Consumer consumer = new Consumer(bank);

        // Producer 쓰레드는 1개, Consumer 쓰레드는 10개를 만들어서 시작시킨다.
        new Thread(producer).start();

        for(int i=0;i<10;i++) {
            new Thread(consumer).start();
        }
    }
}


위의 소스를 실행해 보면 정상적으로 실행될것 처럼 보이나 위의 그림과 같이 0 이하의 값으로 찍히고 있다. 왜그럴까?  wait상태에 있던 쓰레드가  LOCK을 획득하면 wait()함수 다음부터 실행되기 때문이다.
if문 처리되어있던 부분을 while로 변경하여 다시 한번 체크하게 하면 된다.

public class ThreadBank{
    /*
  *  withdraw 함수와 deposit 함수를  synchronized 키워드를 사용 하였다.
  *  한 쓰레드가 withdraw 함수를 실행하는 동안 다른 쓰레드가 deposit 함수를 호출하거나
  *  withdraw 함수를 호출할 수 없다.
  */

    private int money = 0;

    ThreadBank(int money) {
        this.money = money;
    }

    synchronized void withdraw(int value) {

        try {
            // if 문을 사용하여 현재 money 가 0 인지 확인한다.
            while(money == 0)
                wait(); // money 가 0이면 Lock 을 릴리즈하고 대기 상태에 빠진다.

            money -= value;

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Withdraw. money : " + money);

    }

    synchronized void deposit(int value) {
        money += value;

        // wait 을 호출하여 대기 상태에 빠져 있는 모든 쓰레드들을 깨운다.
        notifyAll();

        System.out.println("Deposit. money : " + money);
    }
}

Share:

2018년 3월 27일 화요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 4일차(ClassLoader, TDD)

  • ClassLoader
    • classpath를 참조한다.
    • class 정보를 읽을수 있는게 ClassLoader다.
    • classLoader 한개에 classpath를 다수 가질수도 있다.
    • 예를들어 String을 사용하면 classpath를 참조하여 classLoader가 stirng class를 Metaspace에 올린다. 2번째 호출부터는 Metaspace에 있는 것을 참조한다.
    • 기본적으로 i제공하는 파일을 읽는다.(jdk에 있는 rt.jar등)
    • 부모를 가질수 있다
      • 부모에 있는지 먼저 찾은후 자신의 ClassLoader에서 찾는다.
      • 부모는 자신의 것을 사용하지 못한다.
    • java system <- was <- webapplication 순서를 가질수 있다.(classLoader)
      • system classLoader가 있고 was에서 제공하는 classLoader가 있는데 war를 배포하면 was  가 webapplication classLoader 를 생성해준다.
      • 수정후 재적용시 ClassLoader를 재구동 해야한다. webapplication단계에서 수정했다면 webapplication에서만 재구동 하면 된다.
      • .class파일만 올려서 수정하는 방식도 내부적으로는 webapplication  classLoader가 재구동 되는것이다.
    • java8부터 PermGen이 Metaspace로 변경되었다.(https://dzone.com/articles/java-8-permgen-metaspace)
  • Tomcat
    • 웹어플리케이션 구조(WEB-INF, lib, classes, Web.xml 파일 및 폴더는 고정)
    • was는 처음에 web.xml을 읽는다.
  •  TDD
    • 소스를 알고 있기 떄문에 화이트 테스트를 할수 있다.
    • 경계값을두고 작거나 큰값으로 테스트 할수도 있고 경계값으로 테스트할수도 있다.
    • 100% 길과 경우의 수를 테스트 해야 100%테스트 커러리지가 된것이다.(현실적으로힘들다)
    • 모든 길을 테스트를 다 한다고해서 모든 경우의수를 한것은 아니다.
    • V-MODEL은 프로젝트마다 다르다.(요구사항-분석-설계-구현)
    • 좋은 설계는 좋은 TEST 코드를 만들 수 있다.
    • MOCK(구현이 안되어 있을 경우 가짜객체를 통해 결과값을 정할수 있다)
Share:

2018년 3월 26일 월요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 3일차(Thread, IO)

  • Thread
    • 하나의 객채에 synchronized 가 붙은 메소드가 다수라면 먼저 들어온 쓰레드가 실행되고 나머지 쓰레드는 대기한다.(synchronized가 일부분이라면 synchronized가 붙은 메소드끼리만 대기)
    • 쓰레드가 실행됐을때 run상태와 실행가능 상태를 실행한다.
    • synchronized가 들어가 있는 메소드끼리 lock이 생성되어서 lock에 있는 메소드중에서 호출한 메소드 순서대로 실행된다.
    • Thead 를 직접 상속 받은 경우(class명 extends Thread) start()를 메소드를 실행하면 run()메소드를 실행한다. 하지만 (class명  implements Runnable)으로 구현한 경우 thread객체를 생성 후 작성한 class를 넣어줘서 실행한다.
    • thread는  자신이 Runnable 객체를 가지고 있다면 Runnable run()메소드를 호출하고 아니면 run()메소드를 호출한다.
    • 클래스안에 공유객체가 있을시 서로 동시에 실행 됐을때 문제가있는 메소드 안에 synchronized 로 객체를 동기화 시킨다.
    • wait와 notifyAll로 순서를 제어할수 있다.
  • IO
    • read() 메소드는 byte가 아닌 int로 선언되어있다. EoF를 만났을때 값을 -1 값을 리턴하는데 저장할 곳이 없기때문이다. 
    • 운영체제는 512, 1024btye씩 읽고 사용한다.
  • 직렬화
    • 필드로 구현된 것들도 직렬화를 구현하고 있어야 한다.
    • 기본 타입은 직렬화가 가능하다.
  • freamework는 작업한것을 가져다가 실행해주는 거고 library는 작업자가 가져다 쓰는것이다.
Share:

2018년 3월 24일 토요일

WAS관련 정리

Web.xml(배포기술자)

  • Web.xml은 서블릿 스펙이다. 어떤 WAS든 설정은 같다.
  • context root설정은 WAS마다 다르다.
  • <url-pattern>/</url-pattern> 은 context root 경로 이하인 경로 설정이다.
  • 스프링 웹 MVC 대한 대부분의 설정이 자동으로 되는 것이 많다.
  • @Configuration를 선언할때 사용

Tomcat 과 웹어플리케이션

  • context root는 웹 어플리케이션마다 유일한 값을 가져야 한다. 
  • WAS마다 설정방법이 다르다. (Tomcat, Weblogic 등에 따라 다르다.) 
  • tomcat은 ROOT 라는 이름의 웹어플리케이션은 '/' 로 인식을 한다. 나머지는 보통 폴더이름이 context root가 된다.
  • http://localhost:8080/hello.jsp (ROOT 웹어플리케이션의 hello.jsp) http://localhost:8080/manager/hello.jsp (manager 웹 어플리케이션의 hello.jsp)
  • 예를들어 게시판 웹 어플리케이션(board)가 있다고 가정해보자
    board폴더 안의 내용을 jar로 묶어서 하나의 파일로 만든다. board.war 로 만든다. 
  • tomcat에 배포하려면 어떻게 해야할까?
    webapps폴더에 복사를 하고 tomcat을 실행한다. tomcat이 실행되면서 board.war의 압축을 해제한다. webapps ---- board ---- war파일의 내용이 묶인것이 풀린다.
    http://localhost:8080/board/list.jsp 이런식으로 호출을 할 수 있다.
  • 웹어플리케이션 구조를 가지고 있다면 war파일로 묶지 않아도 구동될수 있다. war파일은 전달하기 편하기 위해 사용.
  • WEB-INF, classes, lib 폴더는 고정적으로 필수로 있다.

intellij 에서 Tomcat

  • target폴더만들어서 배포 시킨후 실행한다.
  • maven프로젝트 인것을 intellij가 자동으로 인식한다.
  • intellij에서 tomcat local로 실행하도록 설정하고 프로젝트 이름이 mvcexam 일 경우에 intellij가 관리하는 tomcat에 IntelliJ가 board.war파일을 만들어서 배포한다.(deploy)

톰캣 디렉토리 구조



  • /bin
    - 톰캣 실행시 사용하는 스크립트 모아둔 곳
  • /conf
    - 웹 어플리케이션에 필요한 설정 파일 모아둔 곳
  • /lib
    - 톰캣에서 사용하는 라이브러리 모아둔곳
  • /logs
    - 오류 정보를 기록하는 로그 디렉토리
  • /temp
    - 임시 파일을 저장하는 디렉토리
  • /webapps
    - 웹 어플리케이션 배포하는 디렉토리
  • /work
    - JSP가 Servlet 컴파일되는 디렉토리

client -----> was 에게 요청시 담기는 정보

  • 요청정보
  • GET / http1.1 : RequestMethod 방식
  • 헤더정보(파라미터, 쿠키, 브라우저정보, 언어정보, OS ....)
  • 빈줄
  • 바디

Tomcat 에서 Web.xml

  • conf 폴더에서 Web.xml
    • DefaultServlet
      • path 가 '/' 이면 모든 요청을 처리한다는 뜻이다.
      • path '/' 설정은 DefaultServlet이 처리 로 예약되어있다.
      • 정적인 파일을 처리하는 로직이 있다.
    • x.jsp, x.jspx 확장자 형식은 JSPSerlvet이 처리한다.


    프로젝트 에서 Web.xml

    • Web.xml 설정
      • path를 '/' 으로 설정하면 설정이 오버라이딩 되어 DispatcherServlet가 모든요청을 처리한다.
        • @Controller, @RestController(@RequestMapping)을 처리한다.
      • 동적인 파일은 DispatcherServlet 에서 처리하고 정적인 파일은 DefaultServlet에서 처리 하도록 한다.(DefaultServlet에 구현되어있기 떄문에 사용)
      • 요청이 오면 DispatcherServlet이 요청받은 path를 찾고나서 없으면 Tomcat의 DefaultServlet한테 넘기고 없으면 404에러가 나온다.(설정을 해야한다.)
      • DispatcherServlet에서 요청온 path를 찾고 없으면 DefaultServlet을 사용한다는 설정
        • 
          @Configuration
          @EnableWebMvc
          @ComponentScan(basePackages = { "com.test.controller" })
          public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {
          
              // default servlet handler를 사용하게 합니다. 
              @Override
              public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
                  configurer.enable();
              }
          }
    Share:

    JAVA로 mini was 만들기

    1.  클라이언트 요청 정보 출력

    프로젝트를 만들고 'WASMain'이라는 Class를 만들고 소스를 아래와 같이 작성한다
    서버에 8080포트를 열고 기다리는 Socket을 생성하고 클라이언트에서 전송한 정보를 출력하는 소스를 작성한다. 아래와 같이 작성 후 Main 메소드를 실행한다.
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class WASMain {
        public static void main(String[] args){
            ServerSocket listener = null;
            try{
                //특정 port에서 기다린는 ServerSocket을 생성한다.
                listener = new ServerSocket(8080);
                System.out.println("client를 기다립니다.");
    
                // 소켓서버 종료될때까지 무한루프
                while(true){
                    // 클라이언트가 접속할때까지 기다린다.
                    Socket client = listener.accept(); // 블러킹 메소드.
                    System.out.println(client);
                    handleSocket(client);
                }
    
            }catch(Exception ex){
                ex.printStackTrace();
            }finally { // finally부분에서 서버소켓을 close한다.
                try {
                    listener.close();
                }catch(Exception e){}
            }
        }
    
        private static void handleSocket(Socket client) throws IOException {
            InputStream in = client.getInputStream(); //클라이언트에게서 받은 데이터를 처리를 위한 작업
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
    
             //1. btye로 한번에 읽어서 출력하기
             /*byte[] buffer = new byte[1024];
             int count = 0;
             while((count = in.read(buffer)) != -1){
                 System.out.write(buffer, 0 ,count);
             }*/
    
             //2. String변수에 담아서 출력 하기
             String line = "";
             while ((line = br.readLine()) != null){
                 System.out.println(line);
             }
    
    
            in.close();
            client.close(); // 클라이언트와 접속이 close 된다.
        }
    }
    

    브라우저에서 'http://localhost:8080'에 접속한다. IDE 툴로 돌아가서 콘솔을 보면 아래와 같이 GET방식으로 요청이 온 정보들이 보일 것이다.(주소창에서 입력해서 접속하는 방식은 GET방식이다.

    2.  Thead 처리 지원하는 WAS

    listener.accept() 부분이 블로킹 메소드라서 요청이 올때 Blocking되는 문제가 있다.  Thread처리가 가능한 WAS로 변경하자.
    Bolcking vs Nonbolcking
    public class WASMain {
        public static void main(String[] args){
            ServerSocket listener = null;
            try{
                //특정 port에서 기다린는 ServerSocket을 생성한다.
                listener = new ServerSocket(8080);
                System.out.println("client를 기다립니다.");
    
                // 소켓서버 종료될때까지 무한루프
                while(true){
                    // 클라이언트가 접속할때까지 기다린다.
                    Socket client = listener.accept(); // 블러킹 메소드.
                    System.out.println(client);
    
                    new Thread(() -> { //jdk 1.8 Lamd형식
                       try{
                           handleSocket(client);
                       }catch (Exception ex){
                           ex.printStackTrace();
                       }
    
                    }).start();
                }
    
            }catch(Exception ex){
                ex.printStackTrace();
            }finally { // finally부분에서 서버소켓을 close한다.
                try {
                    listener.close();
                }catch(Exception e){}
            }
        }
    
        private static void handleSocket(Socket client) throws IOException {
            InputStream in = client.getInputStream(); //클라이언트에게서 받은 데이터를 처리를 위한 작업
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
    
            //String변수에 담아서 출력 하기
            String line = "";
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
    
            in.close();
            client.close(); // 클라이언트와 접속이 close 된다.
        }
    }

    3. 파일 및 이미지 파일 만들기

    브라우저에 출력하기 위해 파일과 이미지를 업로드 한다.
    mac 기준으로 터미널에서 /tmp/wasroot/ 디렉토리를 생성한다.(tmp폴더는 재부팅시 초기화)
    index.html을 만들고 아래와 같이 입력하고
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>index.html</title>
      </head>
      <body>
        Hello World!
        <img src="hello.png" >
      </body>
    </html>
    /tmp/wasroot/ 경로에 이미지 파일을 복사한다.
    hello.png 라는 이미지 파일이 /Users/mac/Downloads/ 경로에 있다고 가정하면 터미널에서 다음과 같이 명령어를 실행한다.
    cp /Users/mac/Downloads/hello.png /tmp/wasroot/hello.png

    4. 원하는 정보만 출력하기

    HttpRequest라는 Class를 만들과 출력할 정보에 관한 set, get 메소드를 생성한다.
    
    public class HttpRequest {
        private String method; //GET, POST, PUT, DELETE ....
        private String path;
        private String host; // host
        private int contentLength; //COntent-Length : body 길이
        private String userAgent; // User-Agent : 브라우저 정보
        private String contentType; // Content-Type : 사용자가 요청한 컨텐츠의 타입
    
        public String getMethod() {
            return method;
        }
    
        public void setMethod(String method) {
            this.method = method;
        }
    
        public String getPath() {
            return path;
        }
    
        public void setPath(String path) {
            this.path = path;
        }
    
        public String getHost() {
            return host;
        }
    
        public void setHost(String host) {
            this.host = host;
        }
    
        public int getContentLength() {
            return contentLength;
        }
    
        public void setContentLength(int contentLength) {
            this.contentLength = contentLength;
        }
    
        public String getUserAgent() {
            return userAgent;
        }
    
        public void setUserAgent(String userAgent) {
            this.userAgent = userAgent;
        }
    
        public String getContentType() {
            return contentType;
        }
    
        public void setContentType(String contentType) {
            this.contentType = contentType;
        }
    
        @Override
        public String toString() {
            return "HttpRequest{" +
                    "method='" + method + '\'' +
                    ", path='" + path + '\'' +
                    ", host='" + host + '\'' +
                    ", contentLength='" + contentLength + '\'' +
                    ", userAgent='" + userAgent + '\'' +
                    ", contentType='" + contentType + '\'' +
                    '}';
        }
    }
    
    WASMain 클래스도 변경한다.
    
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class WASMain {
        public static void main(String[] args){
            ServerSocket listener = null;
            try{
                listener = new ServerSocket(8080);
                System.out.println("client를 기다립니다.");
                while(true) {
                    Socket client = listener.accept(); // 블러킹 메소드.
                    System.out.println(client);
                    new Thread(() -> {
                        try {
                            handleSocket(client);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }).start();
                }
    
            }catch(Exception ex){
                ex.printStackTrace();
            }finally { // finally부분에서 서버소켓을 close한다.
                try {
                    listener.close();
                }catch(Exception e){}
            }
        }
    
        private static void handleSocket(Socket client) throws IOException {
            OutputStream out = client.getOutputStream(); //클라이언트에게 데이터를 보내기 위한 작업
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
    
            InputStream in = client.getInputStream(); //클라이언트에게서 받은 데이터를 처리를 위한 작업
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String line = null;
            HttpRequest request = new HttpRequest();
            line = br.readLine();
            String[] firstLineArgs = line.split(" ");
            request.setMethod(firstLineArgs[0]);
            request.setPath(firstLineArgs[1]);
    
            while((line = br.readLine()) != null){
                if("".equals(line)){ // 헤더를 읽고 빈줄을 만나면
                    break;
                }
                String[] headerArray = line.split(" ");
                if(headerArray[0].startsWith("Host:")){
                    request.setHost(headerArray[1].trim());
                }else if(headerArray[0].startsWith("Content-Length:")){
                    int length = Integer.parseInt(headerArray[1].trim());
                    request.setContentLength(length);
                }else if(headerArray[0].startsWith("User-Agent:")){
                    request.setUserAgent(line.substring(12));
                }else if(headerArray[0].startsWith("Content-Type:")){
                    request.setContentType(headerArray[1].trim());
                }
            }
            System.out.println(request);
    
            String baseDir = "/tmp/wasroot";
            String fileName = request.getPath();
    
            if("/".equals(fileName)){
                fileName = "/index.html";
            }else if(fileName.endsWith(".png")){ //png 이미지일때
                fileName = request.getPath();
            }else{ //잘못된 경로 처리
                fileName = "/error.html";
            }
            fileName = baseDir + fileName;
    
            String contentType = "text/html; charset=UTF-8";
            if(fileName.endsWith(".png")){
                contentType =  "image/png";
            }
    
            File file = new File(fileName); // java.io.File
            long fileLength = file.length();
    
            if(file.isFile()){
                pw.println("HTTP/1.1 200 OK");
                pw.println("Content-Type: " + contentType);
                pw.println("Content-Length: " + fileLength);
                pw.println();
            }else{
                pw.println("HTTP/1.1 404 OK");
                pw.println("Content-Type: " + contentType);
                pw.println("Content-Length: " + fileLength);
                pw.println();
            }
    
            pw.flush(); // 헤더와 빈줄을 char형식으로 출력
    
            FileInputStream fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int readCount = 0;
            while((readCount = fis.read(buffer)) != -1){
                out.write(buffer,0,readCount);
            }
            out.flush();
    
    
            out.close();
            in.close();
            client.close(); // 클라이언트와 접속이 close된다.
        }
    }
    

    5. 브라우저 접속

    브라우저에서 'http://localhost:8080'에 접속한다.
    콘솔과 브라우저에 화면에 아래와  같이 나오면 정상이다.
    POST 방식은 크롬 웹 어플레케이션 'Restlet Client - REST API Testing'을 통해 TEST할수 있다.


    6. 프로젝트 구조

    client에서 서버로 요청하면 accpet()가 실행되고 작업을 thread에게 넘긴후 다시 대기 상태로 돌아간다.
    * GitHub
    Share:

    Blocking 과 NonBlocking

    Blocking이란?


    • Blocking이란 함수를 호출하고 결과가 올 때까지 요청 한 상태에서 멈춰있을때 블록킹이 되었다고 표현합니다.
    • 애플리케이션 실행 시 운영체제 대기 큐에 들어가면서 요청에 대한 system call이 완료된 후에 응답을 보낼 경우
    • Blocking상태에서는 다른 작업을 할 수 없습니다.

    NonBlocking이란?


    • NonBlocking이란 함수를 호출하고 제어권을 반납하여 작업을 계속 진행합니다.
    • 애플리케이션 실행 시 운영체제 대기 큐에 들어가지 않고, 실행 여부와 관계없이 바로 응답을 보낼 경우
    • NonBlocking상태에서는 다른 작업을 진행 할 수 있습니다.





    Share:

    Java char, String 형식 입출력

    • char단위 입출력 클래스는 클래스 이름이 Reader나 Writer로 끝난다.
      • char단위 입출력 클래스를 이용해서 키보드로 부터 한줄 입력 받아서 콘솔 출력
      • System.in - 키보드 입력을 의미 (InputStream )
      • BufferedReader - 한줄씩 입력 받기위한 클래스
      • BufferedReader 클래스의 생성자는 InputStream을 입력받는 생성자가 없다.
      • System.in은 InputStream 타입이여서 BufferedReader의 생성자에 바로 들어갈 수 없으므로 InputStreamReader 클래스를 이용
    • java.io.InputStreamReader/ OutputStreamWriter
      • InputStream/OutStream 클래스의 경우는 byte 단위의 읽기와 쓰기에 사용
      • Java의 Char 와 String의 타입의 경우 Characters로 취급
      • Char / String를 저장하려면 char 단위로 읽고 쓰는 Reader 와 Writer를 사용해야하는데 byte 단위로 데이터를 읽어 Char형태로 변화하여 연결고리 역활을 하는 클래스가 InputStreamReader 와 OutputStreamWriter 이다.
        import java.io.BufferedReader;
        import java.io.FileWriter;
        import java.io.IOException;
        import java.io.InputStreamReader;
        import java.io.PrintWriter; 
        public class CharIOExam01 {
            public static void main(String[] args) {
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                //키보드로 입력받은 문자열을 저장하기 위해 line변수를 선언               
                String line = null;     
                try {
                    line = br.readLine()
                } catch (IOException e) {
                    e.printStackTrace();
                }
                //콘솔에 출력 
                System.out.println(line);
            }
        }
    
    Share:

    2018년 3월 23일 금요일

    mac에서 Intellij SPRING INITIALIZR 프로젝트

    1. SPRING INITIALIZR 

    http://start.spring.io/
    사이트에 접속한다.

    2. 정보 입력 후 다운로드

    Group : examples.boot
    Arifact : demo1
    에 입력 후

    Generate Project 버튼을 선택하여 zip 파일을 다운받고 압출을 푼다.

    3. Intellij 에서 프로젝트 Import

    'close project'  선택 후 'import proejct' 를 선택하여 아래의 그림과 같이 실행한다.
    ※ 'Search for proejcts recursivelt' 항목과 'import maven project automatically'를 선택한다.




    3. COC 개념

    maven은 COC(Convention over configuration) 개념이 적용되어 있다.
    프로젝트로 만들면  main 안에 java ,resource등 정해진 형식에 맞게 폴더를 만들어 준다.
    ※ CoC(Convention over Configuration)는 소프트웨어 개발자가 정해야 하는 수많은 결정들을 줄여주고 단순성을 확보하면서도 유연함을 잃지 않기 위한 설계 패러다임

    4. Maven 으로 실행 해보기

    terminal 에서 다음과 같은 명령어로 실행히 가능하다.

    mvn clean : 초기화
    mvn package : 빌드, 패키지까지 생성
    mvn spring-boot : run : spring boot 웹 어플리케이션 실행

    ※ Maven을 설치하지 않은 경우 'Maven Projects' 탭에서 'Execute MAven Goal' 항목을 선택 한 후 원하는 명령어를 'Comman line'에 입력한다.(Intellij에서 내장된 Maven을 사용하여 실행)


    *GitHub
    https://github.com/lalwr/FastCampusJavaWebMaster/tree/master/demo1
    Share:

    패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 2일차( was실습)

    Share:

    mac 에서 Intellij maven web 프로젝트 에서 Servlet 구현

    1. Maven 프로젝트 생성하기

    1.1. new Module에서  'Create from archetype ' 체크 박스를 선택하고 'maven-archetype-webapp' 을 선택한다.

    1.2. Maven 경로를 설정한다.

    1.3. 원하는 모듈명을 입력하여 생성한다.

    1.4. 아래와 같이 프로젝트가 생성된다.

    1.5. Tomcat에서 'Edit Configurantions' 를 선택 후 'Artifact' 를 선택하고 'war exploded'를 선택한다.



    1.6. 'Build'항목을 선택후 ' Build Artifacts..' 를 선택하고 해당 프로젝트의 'Build'를 선택하여 Build 실행 

    1.7. Tomcat을 실행하여 브라우저에서 접속시 아래와 같은 화면이 나오면 성공

    2.  Maven이란

    2.1. 폴더 구조

    작성 예정

    3.  Servlet 소스 실행 해보기

    3.1. web.xml 수정

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
    
      <servlet>
        <servlet-name>simpleServlet</servlet-name>
        <servlet-class>exam.SimpleServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>simpleServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
      </servlet-mapping>
    </web-app>
    

    3.2. pom.xml 수정

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.example.mvnproject</groupId>
      <artifactId>mvn-project</artifactId>
      <packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>mvn-project Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>4.0.0</version>
        </dependency>
      </dependencies>
      <build>
        <finalName>mvn-project</finalName>
      </build>
    </project>
    

    3.3. Maven Update

    pom.xml 을 수정 했으니 Maven을 Update 한다.


    3.4. Java 폴더 및 파일 생성

    main 폴더에서 'JAVA' Directory를 생성하고 'java' 폴더에서 오른쪽 버튼 선택 후 'Mark Directory as > Sources Root' 를 선택한다.

    3.5. Serlvet Class 파일 생성

    JAVA 디렉토리에서 SimpleServlet 파일을 만들고 HttpServlet을 상속받아 메소드를 Override 하여 구현한다.
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class SimpleServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest reqest, HttpServletResponse response)
                throws ServletException, IOException {
            response.getWriter().println("Hello World!");
        }
    
        @Override
        public void init() throws ServletException {
            System.out.println("Servlet " + this.getServletName() + " has started");
        }
    
        @Override
        public void destroy() {
            System.out.println("Servlet " + this.getServletName() + " has stopped");
        }
    
    }
    

    어노테이션으로 구현하면 아래와 같이 Web.xml에 설정없이 아래와 같이 구현이 가능하다.
    
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    @WebServlet("/HelloServlet")
    public class HelloServlet extends HttpServlet {
        @Override
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
            try {
                out.println("");
                out.println("<html><head></head><body>");
                out.println("<h1>Hello</h1>");
                out.println("</body></html>");
            } finally {
                out.close();
            }
        }
    }
    

    3.6. 작동여부 확인

    아래와 같은 폴더 구조일 것이다.


    Tomcat를 재시작 하여 브라우저에서 아래의 주소를 입력해 본다.
    http://localhost:8080/hello -> 화면에 Hello world! 가 보이면 정상
    http://localhost:8080/HelloServlet -> 화면에 Hello 가 출력되면 정상

    3.7. Tomcat을 Maven으로 변경하여 구동해보기

    web.xml에서 'org.apache.tomcat.maven' 플러그인을 추가한다.
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.example.mvnproject</groupId>
      <artifactId>mvn-project</artifactId>
      <packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>mvn-project Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>4.0.0</version>
        </dependency>
      </dependencies>
      <build>
        <finalName>mvn-project</finalName>
    
        <plugins>
          <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
          </plugin>
        </plugins>
      </build>
    </project>
    

    Run/Debug Configurations 설정 하는곳에서 'Edit Configuration..'를 선택하고
    Maven 을 추가하여 아래의 그림과 같이 'Name'과 'Command Line'을 설정한다.

    설정한 Maven을 선택하고 ▶를 클릭하고 접속했던 주소에 재접속을 시도한다.
    http://localhost:8080/hello -> 화면에 Hello world! 가 보이면 정상
    http://localhost:8080/HelloServlet -> 화면에 Hello 가 출력되면 정상

    * GitHub
    https://github.com/lalwr/FastCampusJavaWebMaster/tree/master/ExamMvnProject

    Share:

    2018년 3월 22일 목요일

    mac 스크린샷 경로 변경

    1. 스크린샷 위치 변경

    defaults write com.apple.screencapture location 경로
    입력후 반영을 위해
    killall SystemUIServer
    를 입력한다.


    2. 기본 경로로 복구
    defaults write com.apple.screencapture location ~/Desktop/ && killall SystemUIServer
    명령어를 입력한다.
    Share:

    mac 에서 Intellij maven 및 jdk 설정하기

    1. maven 다운로드

    http://maven.apache.org/download.cgi
    에 접속하여 bin.tar.gz 파일을 다운로드 받고 압축을 푼다.

    2. maven 폴더 이동

    /Users/mac/programing/apache-maven-3.5.3 경로에 파일이 있다고 가정하면
    터미널에서
    
    mv /Users/mac/programing/apache-maven-3.5.3 /usr/local
    
    를 입력한다.


    ※ Permission denied error 발생 시 아래명령어를 실행한다.
    
    sudo mv /Users/mac/programing/apache-maven-3.5.3 /usr/local

    3. maven repository 변경

    /usr/local/apache-maven-3.5.3/repository로 변경 하고싶다면 아래와 같이 수정한다.

    4. maven 및 jdk 환경설정

    cd
    
    명령어를 입력하고 유저디렉토리로 이동한다.
    
    vi .bash_profile
    
    를 입력 한다.

    i 버튼을 누르고 아래의 내용을 입력한다.

    
    #JAVA
    export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/home
    export PATH=$PATH:$JAVA_HOME/bin
    
    #MAVEN
    export M3_HOME=/usr/local/apache-maven-3.5.3
    export PATH=$PATH:$M3_HOME/bin
    



    입력후 esc 누른후 ':wq' 입력하고 엔터를 누른다.(파일저장후 종료)

    ※ jdk경로 위치 및 버전을 확인 하려면
    cd / Library/Java/JavaVirtualMachines
    
    입력후
    ls
    
    를 입력하면 확인이 가능하다.

    5. 환경설정 반영

    source .bash_profile
    
    를 입력한다.

    6. 메이븐 및 jdk 환경설정 확인하기

    
    mvn -version
    
    
    를 입력하여 아래의 그림같이 나오면 완료.


    
    java -version
    
    를 입력하여 아래의 그림같이 나오면 완료.
    Share:

    2018년 3월 20일 화요일

    서블릿이란?

    1. 서블릿이란??


    • 자바 플랫폼에서 컴포넌트를 기반으로 하는 웹 애플리케이션 개발의 핵심 기술 
    • JSP는 서블릿 기반의 웹 프로그래밍 기술로 내부적으로 JSP는 서블릿으로 변환되어 실행 
    • 고급 웹 프로그래밍 개발을 위해서는 서블릿에 대한 이해가 필요
    • 서블릿의 장점 
      • 자바를 기반으로 하므로 자바API를 모두 사용
      • 운영체제나 하드웨어에 영향을 받지 않으므로, 한번 개발된 애플리케이션은 다양한 서버 환경에서도 실행
      • 웹 애플리케이셔네서 효율적인 자료 공유 방법을 제공
      • 다양한 오픈소스 라이브러리와 개발도구를 활용

    1.1. 웹 애플리케이션 개발에 서블릿 사용 시 이점

    1. MVC 패턴을 쉽게 적용할 수 있고 컨테이너와 밀접한 서버 프로그램을 구현
    2. MVC 패턴을 적요할 때 콘텐츠와 비즈니스 로직을 분리할 수 있으며 컨트롤러와 뷰가 역할을 분담함으로써, 웹 디자이너와 개발자 간에 작업을 원활하게 작업
    3. 리스너 및 필터 서블릿 등 고급 프로그래밍 기법을 통해 더욱 효과적인 웹 애플리케이션을 설계

    2. 서블릿과 서블릿 컨테이너

    • 서블릿 컨테이너는 서블릿을 실행하기 위한 서버 소프트웨어를 말하는 것으로 JSP나 서블릿으로 만들어진 웹 프로그램을 개발하고 실행하기 위한 환경 
    • 대표적으로 아파치, 톰캣 

    3. 서블릿이 동작과정


    • 서블릿은 개발자가 소스 작성 후 컴파일 과정을 거쳐 컨테이너에 배치(deploy)하게 되면 컨테이너에 의해 실행
    • 사용자 요청에 따라 스레드 단위로 실행되면서 비즈니스 로직 및 데이터베이스 연동 등 작업을 수행하고 처리 결과를 사용자에게 HTML 형식으로 전달하는 구조로 동작한다. 



    • 서버에서 서블릿 컨테이너에 의해 실행 되고 생명주기를 가지며 특정 이벤트와 상태가 존재하는 구조 
    • 서블릿 개발은 해당 생명주기 메서드를 오버라이딩하거나 doGet(), doPost()와 같은 사용자 요청 처리 메서드를 구현
    • init()은 서블릿 실행시 한번만 실행되는 메서드이고 service() 메서드는 사용자 요청시 매번 호출되는 메서드이다. destroy()는 서블릿 종료 시 실행되는 메서드이다. 


    4. 서블릿 구조와 생명주기

    4.1. 서블릿 구조와 API


    • JSP와 달리 서블릿은 일반적인 자바 클래스 구조를 뜻하며 컴파일 과정이 필요함 
    • 서블릿은 컨테이너에 의해 실행되므로 특정 클래스를 상속 받아야만 구현할 수 있는 구조
    • 서블릿 개발을 하려면 서블릿 클래스의 상관 관계나 API의 기본 구조를 이해해야 한다. 
    • API(Application Programming Interface)는 특정 클래스를 다른 프로그램에서 사용하기 위해 필요한 정보를 규격
    • 일반적으로 서블릿은  java.servlet.HttpServlet 클래스를 상속
    • javax.servlet.http.HttpServlet 구조 
      • GenericServlet에 비해 HTTP 프로토콜 지원이 포함되어 일반적인 웹 프로그램에 적합
      • HttpServlet도 javax.servlet.GenericServlet을 상속받고 있음
      • 사용자 요청에 따라 GET,POST 방식으로 구별해 처리하지만 경우에 따라서는 구분없이 처리하기도 함 
      • http://www.lalwr.co.kr/index.html 이라는 URL 요청은 HTTP프로토콜에서는 GET/index.html과 같이 서버에 전달됨 
      • HTTP 프로토콜에는 GET,POST,PUT,HEAD,DELETE,OPTIONS,TRACE와 같은 요청이 정의되어 있으며 서블릿에도 각각doGet(), doPOST()와 같은 대응 메서드가 존재함

    4.2. Get 방식

    • 서버에 있는 정보를 클라이언트로 가져오기 위한 방법이다. ex) HTML, 이미지 등
    • 서버에는 최대 처리할수 있는 Byte는 브라우저마다 다르다.(http 2.0기준)
    • QUERY_STRING 환경변수를 통해서 서버로 전달되는데, 다음 형식을 따른다. http://www.lalwr.co.kr/servlet/login?id=admin&name=lalwr 
    • '?'이후의 값들은 서버에서 QUERY_STRING을 통해 전달된다. '키=값'형태로 사용해야 하며 '&'는 여러 속성 값을 전달할 때 연결해주는 문자열이다. 
    • URL이 노출되기 때문에 보안에 문제가 생길 수 있다. 

    4.3. Post 방식

    • 서버로 정보를 전달하기 위해 설계된 방법이다. ex) HTML 폼에 입력한 내용을 서버에 전달
    • 서버에 전달 할 수 있는 데이터 크기에는 제한이 없다. 
    • URL에는 매개변수가 표시되지 않는다.

    5. 서블릿 구조와 생명주기

    5.1. 서블릿 초기화 : init() 메소드


    • 서블릿 실행시 호출되는 메서드로 초기에 한 번만 실행

    5.2. 요청, 응답 : service() 메소드


    • http 요청에 따라 스레드로 실행되는 메서드
    • service() 메소드를 통해 doGet() 혹은 doPost() 메서드를 호출
    • 파라미터인 HttpServletRequest 와 HttpServletResponse를 통해 사용자 요청을 처리한다. 

    5.3. 서블릿 종료 : destory() 메소드


    • 컨테이너로부터 서블릿 종료시 호출되는 메소드 
    • init()와 마찬가지로 한 번만 실행되며
    • 서블릿이 종료되면서 정리할 작업이 있다면 destroy()를 오버라이딩해서 구현

    5.4. 서블릿 구조 예시


    Hello Servlet이 HttpServlet를 상속 하고 있다고 가정할때 요청이 오면 서블릿 컨테이너가 servicer() 메소드를 호출하여 처리한 후 HttpServletResponse객체에 응답을 보낸다.


    Share: