반응형
SMALL

클래스

1. 객체란?

객체 : 쉽게 말해 덩어리. 속성과 동작으로 구성. 사람이 객체라고 치면, 사람은 이름이라는 속성이 있고, 걷다 등의 동작이 가능하다. 있다.

이러한 속성과 동작을 각각 필드(field)와 메소드(method)라고 부른다.

 

이러한 객체로 소프트웨어를 설계하면 객체지향 프로그래밍이 된다.

특징은 캡슐화, 상속, 다형성이 있음.

 

- 캡슐화 : 객체의 필드(=데이터)와 메소드(=동작)를 하나로 묶어서 내부를 감추면 외부의 객체는 알 수 없고 객체가 노출하는 필드와 메소드만 사용 가능하다. 이러면 외부에서 잘못사용해도 객체가 망가질 일이 없음. 

- 상속 : 부모와 자식으로 역할을 부여해서 자식은 부모의 것을 사용가능하다. 단, 부모는 자식꺼를 사용할 수 없음. 코드를 재사용할 수 있기 때문에 효율적임. 그리고 부모를 수정하면 그 아래 자식들이 자동으로 수정된 걸 쓰기 때문에 편함.

- 다형성 :  사용방법은 동일하지만 실행결과가 다양하게 나온다는 뜻. 객체를 바꾸면 프로그램의 실행 결과가 다르게 나올 수 있다.

 

 

2. 인스턴스

 클래스로부터 생성된 객체를 해당 클래스의 인스턴스(instance)라고 부른다. 클래스로부터 객체를 만드는 과정을 인스턴스화라고 함. 동일한 클래스로부터 여러 개의 인스턴스를 만들 수 있는데, 동일한 설계도로 여러대의 자동차를 만드는 것과 같다.

 

클래스 선언은 객체 생성을 위한 설계도를 작성하는 것과 같다.

 

 이 설계도(클래스) 접근 권한을 어떻게 할 것인지는 클래스 앞에 접근권한자를 붙여서 판단한다.

 

[클래스의 접근제한자]

public - 전부 공개(같은 패키지, 다른 패키지 전부 가능)

(default) - 같은 패키지 ㅇㅋ, 다른패키지는 안됨.

 

3. new 클래스()

객체 생성 연산자이다. 객체를 만드는데, 걔 이름이 이거라고 변수에 담아준다.

Student s1 = new Student();
//앞에 있는 Student와 뒤에 있는 Student는 같다.

Student라는 class가 있는데 그걸 new로 객체화해준다. 단, s1이라는 이름에 담아서.

이렇게 되면 인스턴스화 되어서 인스턴스가 생성되었으므로 Student 라는 클래스 안에 있는 애들을 s1 이름으로 불러다 쓸 수 있다.

 

1번 Student 클래스

//Student.java
public class Student{

}

2번 StudentExample 클래스

//StudentExample.java

public class StudentExample {

	public static void main(String[] args) {
		
		Student s1 = new Student();
		System.out.println("s1 변수가 Student 객체를 참조합니다." + s1);
		
		Student s2 = new Student();
		System.out.println("s2 변수가 또다른 Student 객체를 참조합니다.");
	}
}

총 2가지의 클래스가 있는데 클래스는 Student 처럼 실행은 못하지만 다른 클래스가 사용할 수 있도록 라이브러리 역할을 하는 클래스가 있고, StudentExample  처럼 main()메소드를 가지고 있어 실행 가능한 클래스가 있다.

 

4. 클래스 구성 멤버(필드, 생성자, 메소드)

public class 요소 {
	//--------- 필드 선언 ------------
	String company = "현대자동차";
	String 문자1;
	String 문자2;
	Boolean 불린;
	int 숫자;
	//--------- 아이템 생성 끝 ------------
	
	//-------- 여러개의 생성자 선언 ------------
	/*왜? 생성자가 있어야 쓸 수 있는데(조합 어떻게 갖다씀?)
	순서에 따라서 뭘 갖다쓸지 모르니까.*/

	//첫번 째 생성자
	public 요소(){}
	
	//두번 째 생성자
	요소(String company, int 숫자){
		this.company = company;
		this.숫자 = 숫자; //야 숫자 좀 받아줘
	}
	
	//3번 째 생성자
	요소(String company, String 문자2, Boolean 불린){
		this.company = company;
		this.문자2 = 문자2;
		this.불린 = 불린;
	}
}

main()이 없는 라이브러리형 클래스의 경우, main()이 선언된 실행 클래스에서 가져가기 위해 작업이 필요하다.

 

1) 필드는 변수 선언과 비슷하다. 쉽게 말해서 값 담는 그릇임.

java는 javascript와 다르게 변수 타입(형)이 굉장히 중요하기 때문에 필드에 알맞는 형(그릇의 재질처럼)을 부여해준다.

 

이 필드가 외부에서 마음대로 값을 읽고 변경하면 무결성이 깨지므로, getter/setter를 사용해서 들어갔다가 나오는 통로를 만들어준다.

 

2) 생성자는 쉽게 말해 그릇의 묶음이다.

필드가 값을 담는 그릇이라 다양한 재질(String, Boolean 등)이 선언되어 있는데 main()이 있는 실행클래스에서 뭘 갖다쓸지 모른다. 이 때 생성자를 호출하면 비어있는 껍데기를 템플릿처럼 가져와서 초기화할 수 있음.

 

위에서는 main()을 가진 실행 클래스가 company와 숫자 묶음을 호출하면 두번째 생성자를 호출할 것이고, company와 문자, 불린 묶음을 호출하면 세번째 생성자를 호출할 것이다. (첫번째꺼는 기본 생성자로 값이 들어있는 company만 가능)

 

나는 라이브러리형 클래스를 s1으로도 가져오고, 또 s2로도 가져오고 해서 템플릿을 다양하게 가져와서 복사해서 쓸꺼다. 그러면 한개 이상의 생성자를 쓴다면 해당 묶음의 재질(형)에 따라서 다양하게 활용 가능하다. 물론 캡슐화도 가능!

 

=> 이렇게 매개변수를 달리하는 생성자를 여러개 선언하는 것을 생성자 오버로딩이라고 한다.

 

중복된 생성자의 경우, this로 묶어서 사용 가능.

	//다른거 불러와
	Car(String model){
    	this(model, "은색", 250);
	}
	
	//불러와지는 생성자
	Car(String model, String color, int maxSpeed){
		this.model = model;
		this.color= color;
		this.maxSpeed = maxSpeed;
	}
}

 

 

3) 메소드는 객체의 동작이다.

public class Calculator {

	void powerOn() {
		System.out.println("전원을 켭니다");
	};
	
	void powerOff() {
		System.out.println("전원을 끕니다");
	}

	int plus(int x, int y) {
		int result = x + y;
		return result;
	}
    
    double plus(double x, double y) {
        double result = x + y;
        return result;
	}
}
public class CalculatorExample {
	
	public static void main(String[] args) {
		Calculator myCalc = new Calculator();
		
		myCalc.powerOn(); //실행됨
		
		int result = myCalc.plus(3,5); 
		System.out.println(result); //실행하고 찍음
	}
}

 

라이브러리 클래스인 Calculator에는 powerOn, powerOff, plus 와 같은 메소드가 있다. 

return 해서 결과값을 전달하거나, 아니면 리턴값이 없는 경우 void를 선언해서 동작만 한다.

뱉는거 아니면 움직이기만 하는거임.

 

라이브러리 클래스에서 powerOn() 이라는 클래스를 void로 선언했다면 그 동작을 main()이 선언된 실행 클래스에서 가져다 썼을 때 리턴값은 없지만 powerOn 안에 선언된 행동은 한다.(sysout을 뱉는다.)

 

return 하면 종료의 의미이다. 뒤에 리턴값이 있다면 멈추고 값을 뱉어내는 것.

 

만약 plus를 부를 때 값을 double 값을 넣고 호출하면 double plus 에 있는 값이 호출된다.

=> 매소드 이름은 같은데 매개변수를 달리하는 메소드를 여러개 선언하는 것을 메소드 오버로딩이라고 한다.

 

4.) 정적 멤버(static)

필드(그릇)과 메소드(동작)은 기본적으로 객체를 생성해야만 사용할 수 있지만, 그냥 객체 없이도 고정적으로 사용할 수 있는 정적 멤버를 만들 수 있다.

 

즉, new 하지 않아도 갖다쓸 수 있음. 정적 필드와 정적 메소드가 생길 수 있다.

 

public class Calculator {

	static double PI = 3.141592; //파이는 변경될일 없는 값이라 정적으로 선언
    
    static plus(int x, int y){
    	~~~
    }
}

 

이렇게 정적인거 갖다쓰는 경우엔 아래와 같다.

double result = 10 * 10 * Calculator.PI;
int result2 = Calculator.plus(10,5);

 

 

다만 이건 다른게, 객체생성을 하는 new()로 만든 인스턴스 필드와 인스턴스 메소드를 사용할 수 없다. 즉, static 한 애에게 다른 멤버도 추가해주거나 변경해주고 싶은 경우 new()로 인스턴스로 복사해서 그걸 써야하는 것.

 

참고로 main()함수도 static이 붙은 정적 메소드이므로, 객체 생성 없이 인스턴스 필드와 인스턴스 메소드 사용이 불가하므로 객체 생성 후에 갖다써야 한다.

 

5) 값 변경 불가할 땐 final 필드와 상수

final이 붙으면 값 변경 못한다고 보면 된다. static 붙으면 불변의 다 갖다쓸 수 있는 값, 즉, 상수가 되는거임.

 

 

6) 필드, 생성자, 메소드의 접근제한자

[클래스의 접근제한자]

public - 전부 공개(같은 패키지, 다른 패키지 전부 가능)

(default) - 같은 패키지 ㅇㅋ, 다른패키지는 안됨.

 

클래스는 이 두개만 되지만 그 내부의 필드, 생성자, 메소드는 몇개 더 사용 가능하다.

 


[필드, 생성자, 메소드의 접근제한자]

public - 전부 공개(같은 패키지, 다른 패키지 전부 가능)

protected - 같은 패키지이거나, 자식 객체만 사용 가능

(default) - 같은 패키지 ㅇㅋ, 다른패키지는 안됨.

private - 현재 클래스 내부에서만 사용 가능.

 

 

7) 싱글톤 패턴

애플리케이션 전체에서 단 한개의 객체만을 생성해서 사용하는 것. (=private로 생성자 접근제한해서 외부에서 new 못하게 막음) 객체 얻는 것은 getInstance() 메소드 호출로만 가능하다.

 


상속

프로그램에서는 상속은 자식이 부모를 선택한다.

public class 자식클래스 extends 부모클래스 {

}

 

부모클래스는 여러개일 수 없다. 단, 각 자식클래스는 동일한 부모클래스를 상속할 수 있다.

 

자식클래스 변수 = new 자식클래스();

부모 없는 자식 없듯이 이렇게 자식 객체를 생성하면 부모가 자동으로 생성된다. 즉, extends 를 해놓은 부모클래스는 객체 생성 시 함께 생성되는 거다.(물론 눈에 보이지는 않지만)

 

만약 plus를 부를 때 값을 double 값을 넣고 호출하면 double plus 에 있는 값이 호출된다.
=> 매소드 이름은 같은데 매개변수를 달리하는 메소드를 여러개 선언하는 것을 메소드 오버로딩이라고 한다.

 

위에서 설명한 이 메소드 오버로딩을 자식이 부모한테 쓸 수 있다.

즉, 부모한테 상속받아 가져온 것을 자기가 재정의해서 입맛대로 사용하는 것.

단, Override 라는 어노테이션을 붙여준다.

 

public class Calculator {

	public double areaCircle(double r){
    	Sysyem.out.println("Calculator 객체 안의 areaCircle 입니다");
        return 3.14159 * r * r;
}
public class Computer extends Calculator {

	@Override
	public double areaCircle(double r){
    	Sysyem.out.println("Calculator 객체 안의 areaCircle메소드를 오버라이딩");
        return Math.PI * r * r;
}
public class ComputerExample {
	public static void main(String[] args) {
    
    	int r = 10; //원의 반지름
        
      //그냥 기본적인 부모 메소드의 값
      Calculator calculator = new Calculator();
      System.out.println(calculator.areaCircle(r)); //314.159
      
      //자식이 갖다가 오버라이딩 해서 쓴 메소드 값
      Computer computer = new Computer();
      System.out.println(computer.areaCircle(r)); //314.15926535...  
	}
}

 

이렇게 나온다는 것!

 

 

final

동일하게 값을 변경 못하므로 클래스에 붙으면 상속이 불가하고, 메소드에 붙으면 오버라이딩을 못한다.

 

타입 변환

자식은 부모의 특징과 기능을 상속받았기 때문에 부모와 동일한 취급을 받을 수 있다. 즉, 자동으로 타입이 변환된다.

물론 부모걸로 자동 타입이 변환되면 부모클래스의 필드와 메소드만 접근 가능하다.

 

하지만 반대로 부모는 자식 타입으로 자동변환 되지 않는다. 이 경우 casting 연산자로 강제 타입 변환을 한다.

 

Parent parent = new Child(); //자동 타입 변환
Child child = (Child) parent; //강제 타입 변환

 

추상클래스(abstract)

새, 곤충, 물고기 클래스가 각각 있는데 공통되는 부분이 있어서 그걸 따로 묶고싶다. 그러면 이걸 추상클래스로 만들어서 상속시킨다.

public absract class Phone {
	void trunOn(){ //핸드폰들은 공통적으로 켜는 기능을 가짐
    	...
    }	
}

 

 

봉인된(Sealed) 클래스

Java15 부터 무분별한 자식 클래스 생성을 방지하기 위해서 봉인된(Sealed) 클래스가 도입되었다.

 

 

반응형
LIST
반응형
SMALL

스프링 프레임워크 (Spring Framework)

🍀 스프링(Spring) 이란?

자바 엔터프라이즈 개발을 편하게 해주는 오픈 소스 경량급 애플리케이션 프레임워크

- JAVA로 다양한 어플리케이션을 만들기 위해 개발을 더 쉽게 할 수 있도록 도와주는 프레임워크

- 동적인 웹 사이트를 개발하기 위한 여러 가지 서비스를 제공(jsp, MyBatis, JPA 등등)

- 전자정부 표준 프레임워크의 기반 기술로서 쓰이고 있다.

- 중복코드 사용률을 줄이고 비지니스 로직을 더 간단하게 해주며, 오픈소스를 좀 더 효율적으로 가져다 쓸 수 있음.

 

🍀 스프링의 특징

˙ 경량 컨테이너로서 자바 객체를 직접 관리한다.

˙ POJO(Plain Old Java Object) 방식의 프레임워크

    - POJO : 단순하고 가벼운 자바 객체(우리가 자바에서 개발하는 지극히 평범한 객체)

˙ IoC(Inversion of Control; 제어 반전) 지원

    - 필요에 따라 컨트롤의 제어권을 사용자가 갖지 않고 스프링에서 사용자의 코드를 호출

˙ DI(Dependency injection; 의존성 주입)를 통한 객체 간의 관계 구성

˙  AOP(Aspect-Oriented Programming; 관점 지향 프로그래밍) 지원

˙ 영속성과 관련한 다양한 서비스 지원

    - iBATIS, 하이버네이트 등 데이터베이스 처리 라이브러리와 연결할 수 있는 인터페이스 제공

˙  확장성이 높다.

    - 수많은 라이브러리가 스프링에서 지원되고 있기 때문에 사용에도 라이브러리를 별도로 분리하기도 용이하다.

 

🍀 스프링의 개발을 더 쉽게 해주는 기술들

1.  POJO(Plain Old Java Object) 방식

- POJO는 Java EE를 사용하면서 해당 플랫폼에 종속되어 있는 무거운 객체들을 만드는 것에 반발하여 나타난 용어이다.
- 별도의 프레임 워크 없이 Java EE를 사용할 때에 비해 인터페이스를 직접 구현하거나 상속받을 필요가 없어 기존 라이브러리를 지원하기 용이하고, 객체가 가볍다.
- 즉, getter/setter를 가진 단순한 자바 오브젝트를 말한다.

기존에는 프레임워크가 너무 무겁고 내용도 방대했다. 이러한 니즈를 충족하기 위해 경량 프레임워크인 스프링이 등장했다. 기존에 Java EE의 경우 미리 설계되어있는 인터페이스나 클래스를 상속받아서 무거운 객체들을 만들어야만 했는데, Spring은 일반적인 java 코드만으로 객체를 구성할 수 있게 된다. 따라서 더 유연하고 가볍게, 생산성을 높이며 프로그래밍이 가능해진다.

 

▼ JAVA EE란?

더보기

JAVA EE는 엔터프라이즈 에디션의 자바 플랫폼이다.

  • 자바 플랫폼 Java SE  (Standard Edition)
  • 자바 플랫폼 Java EE  (Enterprise Edtion)
  • 자바 플랫폼 Java ME (Micro Edtion)
  • Java FX 

모든 자바 플랫폼들은 자바 가상 머신(JVM)과 API로 구성되어 있다. JVM이 어플리케이션을 동작시키기 위한 프로그램이고 API는 개발에 필요한 함수들을 패키지로 묶어서 배포한다.

기본은 JAVA SE가 스탠다드라는 이름 답게 흔히 많이 쓰는 java.lang.*, java.io.*, java.util.* 등등 java 프로그래밍 언어를 배울때 사용하는 대부분의 패키지를 포함한다.

 

그렇다면 JAVA EE는 뭘까? JAVA SE 위에 구축된 버전으로 대규모, 다계층, 확장 가능한 특징이 있으며 대규모일 때 안정적이고 안전한 네트워크 애플리케이션을 개발 및 실행하기 위한 API를 추가로 포함한다. JAVA EE가 servlet, JSON, REST API, 웹소켓 등을 지원한다.

 

근데 이를 대규모로 지원하려다보니 용량도 크고 포함한 패키지가 많아서 속도가 느려지기도 한다는 말이다.


 

2. IoC(Inversion of Control, 제어 반전)

Spring에 가장 핵심적인 기능. 한마디로 알아서 해주는 비서가 하나 생겼다.

개발자는 JAVA 코딩시 new 연산자, 인터페이스 호출, 데이터 클래스 호출 방식으로 객체를 생성하고 소멸시킨다.

IoC란 인스턴스 (객체)의 생성부터 소멸까지 객체 생명주기 관리를 개발자가 하는게 아닌 스피링(컨테이너)가 대신 해주는 것을 말한다.

IoC는 개발자가 실수할 수 있는 생명주기 관리를 대신 해준다. 프로젝트 규모가 커질수록 객체와 자원을 이용하는 방법이 더 복잡해져 코드가 꼬일 수 있는데 이를 Spring의 IoC가 대신 자동 관리해준다.

ex) Spring IoC Container 에 Bean으로 등록된 것들을 의존성 주입하기 위해 어노테이션 @Autowired를 사용한다.

단, 제어권은 개발자가 아닌 IoC에게 있으며 IoC가 개발자의 코드를 호출하여 그 코드로 생명주기를 제어한다.

 

3. DI(Dependency Injection, 의존성 주입)

프로그래밍에서 구성요소 간의 의존 관계가 소스코드 내부가 아닌 외부의 설정파일을 통해 정의되는 방식이다.
코드 재사용을 높여 소스코드를 다양한 곳에 사용할 수 있으며 모듈간의 결합도도 낮출 수 있다.

쉽게 말하자면 게임 캐릭터라는 하나의 객체가 존재하는데, 그 객체를 더 잘 이용하기 위해서 무기, 방패 등 아이템을 가져와 결합시키는 것이다. 이 객체는 무기와 방패를 뺐다 꼈다 자유자재로 할 수 있으며 아이템을 갈아끼우는데 어떤 상황에 구애받지도 않는다.(그리고 그 아이템을 갈아끼우는걸 IoC Container가 해준다.)

JAVA에서 데이터를 저장하고 가져오는 기능을 외부의 Oracle Database를 사용할 수도 있고, JDBC, iBatis, JPA 등 다른 프레임 워크를 이용해 짤 수도 있다. 이때 Spring을 이용하면 그때마다 필요한 부분을 뺐다 꼈다 하면서 적절한 상황에 필요한 기능을 해낼 수 있다.

 

▼ Spring은 DI를 지원하는 조립기다. 의존성 주입을 지원하는 방식은 크게 3가지이다.

 

더보기

1) 생성자 주입

public class Car {
    private Tire tire;

    public Car(Tire tire) {
        this.tire = tire;
    }
}

생성자 주입은 위에서 보았던 예시처럼 생성자를 사용해서 외부에서 주입을 해주는 것.

 

2) setter 주입

public class Car {
    private Tire tire;

    public Tire getTire() {
        return tire;
    }

    public void setTire(Tire tire) {
        this.tire = tire;
    }
}



public class Client {
    public static void main(String[] args) {
        Tire tire = new KoreaTire();
        Car car = new Car();
        car.setTire(tire);   // setter 의존성 주입
    }
}

생성자를 통해 의존성을 주입하면 한번 장착한 타이어는 더 이상 타이어를 교체할 수 없다는 문제점이 존재한다. 운전자가 원할 때 타이어를 교체하고 싶다면 setter 의존성 주입을 사용해야 한다.

 

3) 필드 주입

 생성자 의존성 주입을 할 때도 생성자에 실수로 필드를 적지 않을 수 있다. 이러면 컴파일 에러가 발생하지 않기 때문에.. 테스트 코드를 실행해보기 전까지는 알 수 없다.

 

그래서 이러한 경우를 사전에 방지하고자 필드에 final 키워드를 사용하는 것을 권장한다. final 키워드가 붙어있는데 생성자에 초기화 되지 않는다면 컴파일 에러가 발생하기 때문에 개발자의 실수를 사전에 막을 수 있다는 장점이 있다.


 

 

4. AOP(Aspect Object Programming, 관점 지향 프로그래밍)

AOP : 관점별로 나눠 모듈화해서 필요할때마다 끼워쓴다.

어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어 보고 그 관점을 기준으로 각각 모듈화하는 방법이다. 즉, 코드를 부분적으로 나눠서 중복되는 코드들을 Aspect(관점별로)를 이용해서 모듈화한(=묶는)다.

로깅, 트랜잭션, 보안 등 여러 모듈에서 공통적으로 사용하는 기능을 분리하여 관리 할 수 있다.

각각의 클래스가 있다고 가정하자. 각 클래스들은 서로 코드와 기능들이 중복되는 부분이 많다. 코드가 중복될 경우 실용성과 가독성 및 개발 속도에 좋지 않다. 중복된 코드를 최대한 배제하는 방법은 중복되는 기능들을 전부 빼놓은 뒤 그 기능이 필요할때만 호출하여 쓰면 훨씬 효율성이 좋다.

즉, AOP는 여러 객체에 공통으로 적용할 수 있는 기능을 구분함으로써 재사용성을 높여주는 프로그래밍 기법이다.

 

5. PSA (Portable Service Abstraction, 일관된 서비스 추상화)

환경의 변화와 관계없이 일관된 방식의 기술로의 접근 환경을 제공하려는 추상화 구조를 의미한다. POJO 원칙에 따라 가벼워지고 생산성이 높아진 Spring은 PSA 방식으로 추상화가 되어있어 가능하다.

Java Framework에서 사용 가능한 라이브러리들은 다양하지만 각자의 사용 방법이 다르다. 만약 MySQL 사용하던 시스템에서 DB를 Maria DB로 변경한다면 기존 소스를 일일히 수정해줘야 하지 않겠는가? 이럴 때 Spring을 사용하면 동일 사용방법을 유지한 채로 DB를 변경할 수 있다. Spring이 데이터베이스 서비스를 추상화한 인터페이스를 제공해주기 때문이다.(이 경우 Java를 이용해서 DB에 접근하는 방법을 규정한 인터페이스를 JDBC라고 한다.)

쉽게 말해 중간 어댑터(Adapter)가 하나 있는 것이다. 같은 일을 하는 다수의 기술을 공통의 인터페이스로 제어할 수 있게 한다.

 

🍀 Spring  MVC 구조

  • 모델-뷰-컨트롤러 패턴 : 소프트웨어 디자인 패턴 중 하나
  • M (Model) / V (View) / C (Controller)
    • Model : 어플리케이션의 정보나 데이터, DB 등을 말합니다.
    • View : 사용자에게 보여지는 화면, UI를 말합니다. 모델로부터 정보를 얻고 표시합니다.
    • Controller : 데이터와 비즈니스 로직 사이의 상호 동작을 관리합니다. 즉, 모델과 뷰를 통제합니다. MVC 패턴에서 View와 Model이 직접적인 상호 소통을 하지 않도록 관리합니다.

MVC 패턴은 크게 MVC 1 패턴과, 스프링이 채택한 MVC 2 패턴으로 나눌 수 있습니다.

MVC1

MVC1 패턴의 경우 View와 Controller를 모두 JSP가 담당하는 형태를 가집니다. 즉 JSP 하나로 유저의 요청을 받고 응답을 처리하므로 구현 난이도는 쉽습니다.

단순한 프로젝트에는 괜찮겠지만 내용이 복잡하고 거대해질수록 이 패턴은 힘을 잃습니다. JSP 하나에서 MVC 가 모두 이루어지다보니 재사용성도 매우 떨어지고, 읽기도 힘들어집니다. 즉 유지보수에 있어서 문제가 발생합니다.


MVC2

MVC2 패턴은 널리 표준으로 사용되는 패턴입니다. 요청을 하나의 컨트롤러(Servlet)가 먼저 받습니다. 즉 MVC1과는 다르게 Controller, View가 분리되어 있습니다. 따라서 역할이 분리되어 MVC1패턴에서의 단점을 보완할 수 있습니다. 그러므로 개발자는 M, V, C 중에서 수정해야 할 부분이 있다면, 그것만 꺼내어 수정하면 됩니다. 따라서 유지보수에 있어서도 큰 이점을 가집니다.

MV2는 MVC1 패턴보다 구조가 복잡해질 수 있지만, 개발자가 이러한 세부적인 구성까지 신경쓰지 않을 수 있도록 각종 프레임워크들이 지금까지 잘 발전되어 왔습니다. 그 중에서 대표적인 것이 바로 스프링 프레임워크입니다.

 

스프링 프레임워크 MVC2 패턴

스프링에서는 유저의 요청을 받는 DispathcerServlet이 핵심입니다. 이것이 Front Controller의 역할을 맡습니다.

Front Controller(프런트 컨트롤러)란, 우선적으로 유저(클라이언트)의 모든 요청을 받고, 그 요청을 분석하여 세부 컨트롤러들에게 필요한 작업을 나눠주게 됩니다.

 

즉, Front Controller

1. 클라이언트 요청에 맞는 Controller 클래스에 매핑해주는 HandlerMapping에게 검색을 요청하고 => "야 찾았어!"

2. 위에서 매핑된 Controller가 비지니스 로직을 수행하고 => "일하는중"

3. 로직을 수행한 결과물들을 가지고 있는 ViewResolver에게 "이런 이름을 가진 view를 줘" 라고 요청하고 => "결과물 여기"

4. ViewResolver에게 받은 알맞은 결과물을 클라이언트에게 결과화면으로 리턴합니다. => "니가 원하던거 줄께"

 

와 같은 역할을 하게 됩니다.


스프링 부트 프레임워크 (Spring Boot Framework)

🍀 스프링 부트(Spring Boot) 란?

스프링이 기존 기술에서 복잡성을 줄인 프레임워크지만, 그럼에도 불구하고 사용 시 여러 사항들을 설정해줘야 한다.
Spring Boot는 이러한 설정 내용을 간략히 줄여준 프레임워크다. 그렇게 될 수 있는 이유는 Spring Boot가 기존의 복잡한 설정을 대신 해주기 때문이다.
 
Spring Boot는 자체적인 웹 서버를 내장하고 있어, 기존 스프링보다 빠르고 간편하게 배포할 수 있다. 또한 독립적으로 실행 가능한 Jar 파일로 프로젝트를 빌드할 수 있어, 클라우드 서비스 및 도커와 같은 가상화 환경에도 빠르게 배포 가능하다.

 

반응형
LIST
반응형
SMALL

컨트롤러에서 요청/응답 처리하는 법

protected void doProcess(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {

하나하나 뜯어보자면,

protected : java 접근자, 같은 폴더(패키지)및 그 클래스를 상속(extends)해서 구현하는 경우 접근이 가능 
void : return 되는 타입이 없음을 의미 
HttpServletRequest,HttpServletResponse : 웹브라우저 URL로 servlet이 요청할 시 요청,응답을 받기 위해 만드는 객체. 매개변수로 가지고 있는거임. WAS가 웹브라우저로부터 Servlet 요청을 받으면 req객체 생성해서 저장하고 resp 객체를 생성해 응답을 담아 servlet에게 반환한다. 
throws ServletException,IOException : java.io.IOException 과 javax.servlet.ServletException 예외를 던져야 합니다. 그냥 서블릿 규칙임.

 

HttpServletRequest 과 HttpServletResponse 메소드 정리

HttpServletRequest 과 HttpServletResponse 메소드 정리 HttpServletRequest 를 간단하게 req라고 해봅시다. req를 사용하면, 값을 받아올 수가 있는데, 회원정보를 보냈다면 req 객체 안에 모든 데이터들이 들어가

heannim-world.tistory.com

 

반응형
LIST
반응형
SMALL

HttpServletRequest 과 HttpServletResponse  메소드 정리

HttpServletRequest 를 간단하게 req라고 해봅시다. req를 사용하면, 값을 받아올 수가 있는데, 회원정보를 보냈다면 req 객체 안에 모든 데이터들이 들어가 있다. 따라서 req 객체의 몇가지 메소드들을 사용해서 원하는대로 꺼내쓰면 됨.

HttpServletRequest 메소드 메소드 설명
req.getMethod() get방식과 post방식을 구분할 수 있다.
req.getSession() 세션 객체를 얻는다.
req.getProtocol() 해당 프로토콜을 얻는다.
req.getParameter() 원하는 데이터를 꺼낼때(반환타입 String)
req.getContextPath()  프로젝트 Path만 가져옵니다.
req.getRequestURI()  프로젝트 + 파일경로까지 가져옵니다.
req.getRequestURL() 전체 경로를 가져옵니다.
req.getQueryString()
쿼리스트링을 얻는다.
req.ServletPath()  파일명만 가져옵니다.
req.getRealPath()  서버 or 로컬 웹 애플리케이션 절대결로 가져옵니다. 
req.setCharacterEncoding("UTF-8") POST방식으로 보내는 값이 '한글'일 경우 깨지지 않게 전달하기 위해 사용(GET은 톰캣에서 기본 UTF-8 적용되어있음)
req.setContentType("text/html;charset=utf-8") 서블릿에서 직접 브라우저에 출력해줄경우 브라우저에게 어떤 인코딩 방식을 쓸 것인지 전달
req.getwriter() java.io의 PrintWriter 클래스를 리턴 타입으로 한다. PrintWriter 클래스는 바이트를 문자 형태 객체바꿔주는데 클라이언트에게 문자형태로 응답하고 싶기 때문. getWriter()는 '쓰기'로 응답하겠다는 말로, 응답으로 내보낼 출력 스트림을 얻어낸 후 out.print(HTML태그) 를 써서 스트림에 텍스트를 기록한다.

HttpServletResponse를 간단하게 resp라고 해봅시다. HttpResponseServlet을 사용하여 Http Response 메시지를 생성/응답한다.

HttpServletResponse 메소드 메소드 설명
resp.setContentLength() 컨텐츠 길이 설정
resp.setHeader()  응답하는 데이터의 타입
resp.setStatus("응답코드") 응답코드를 지정할 수 있다. http 응답코드 200으로 적어도 되지만 이미 선언되어있는 상수를 사용하는게 의미 있는 값으로 사용할 수 있음.
resp.setCharacterEncoding("UTF-8") 응답할 때 문자의 인코딩 형태를 구한다.
resp.setContentType("application/json") 서블릿에서 직접 브라우저에 출력해줄경우 브라우저에게 어떤 인코딩 방식을 쓸 것인지 전달.
application/json은 utf-8이 스펙상 지정되어 있어 Response Header Content-Type에 charset을 추가해줄 필요가 없다.
addCookie(cookie) 쿠키를 지정한다.
sendRedirect(URL) 지정한 URL로 이동한다.
resp.getwriter() java.io의 PrintWriter 클래스를 리턴 타입으로 한다. PrintWriter 클래스는 바이트를 문자 형태 객체바꿔주는데 클라이언트에게 문자형태로 응답하고 싶기 때문. 응답으로 내보낼 출력 스트림을 얻어낸 후 out.xx(HTML태그) 를 써서 스트림에 텍스트를 기록한다.
resp.getOutputStream()
출력스트림에 접근하여 읽고 쓰는 등의 작업을 한다.

ActionForward란?

Action이 모든 작업을 끝내고서 이동하는 위치을 가상적으로 지정한 것이 ActionForward이다.
브라우저요청 -> ActionServlet -> [ActionForm] -> Action -> ActionForward의 path에 의해 지정된 다른 웹 요소

참고 : https://cobook.tistory.com/8

반응형
LIST
반응형
SMALL

jQuery 를 이용하여 id, class, name 의 input value 값 가져오기

<input type="text" id="inputId" class="inputClass" name="inputName">

 

1) id 값 기준으로 가져 오기

var valueById = $('#inputId').val();

# 은 아이디를 의미

2) class 값 기준으로 가져 오기

var valueByClass = $('.inputClass').val();

. 은 클래스를 의미

3) name 값 기준으로 가져 오기

var valueByname = $('input[name=inputName]').val();

input 태그의 name값을 그대로 입력

반응형
LIST
반응형
SMALL

서블릿 기초를 다시 복습하고 싶어서 정리를 해보았다.
출처 : 유투브 뉴렉쳐 님의 2020 Servlet&JSP 프로그래밍 강의.(링크 클릭)

▼ 앞에 포스팅부터 보고 오십셔.

 웹 서버 프로그램 구조

[요약]

1. 클라이언트한테 요청을 받으면 서버가 DB에서 웹문서를 찾아본다. 있으면 그냥 바로 전달한다.(=정적인 페이지 ex.로그인 페이지 이동)
2. 원하는게 없다. 그러면 그걸 찾을 수 있는 서블릿 컨테이너 속 코드(서버 앱)를 찾는다. 
3. WAS가 자바 언어로 된 서블릿을 실행해서 동적인 페이지를 만든다.
4. 다시 클라이언트한테 응답한다.

 

클라이언트와 서버 : 요청자와 제공자


 

클라이언트와 서버


웹을 통해 통신하는 양 끝에는 클라이언트서버가 있다. 클라이언트는 요청자, 서버는 제공자(DB)이다. 클라이언트는 우리가 사용하는 웹 브라우저(Chrome, Edge, Safari) 등을 이용해서 정보를 요청한다. 클라이언트가 요청하면 서버는 DB를 뒤져서 원하는 요청사항에 대한 답을 제공해준다.

그런데 만약 이 시스템에 무언가 변경사항이 있다고 생각해보자.

클라이언트와 서버는 한 쌍이다. 이 두개가 동기화가 되어 있고, 변경사항은 양쪽 다 반영이 되어야 한다. 그러나 서버는 하나라서 한번만 변하면 되지만 클라이언트는 사용자의 수에 따라 여러명이므로 각각 업데이트 해야 한다. 

때문에 예전에는 소프트웨어 업데이트가 자동 업데이트가 아니라 재설치의 개념이었다. 이 뿐만 아니라 다른 프로그램의 영향도 받아서 서버가 업데이트 내용을 배포하기도 힘들고 클라이언트가 각 브라우저마다 업데이트 하기에도 힘들었었다. (그래서 예전에 발매된 게임은 직접 스토어에 가서 업데이트 버튼을 눌러 다운받지 않으면 안되었다. 그래서 예전버전 사용하던 사람들이 많고 관리가 힘드니 2탄이 나오는거임....)

그래서 웹(Web)이라는 것이 등장했다.

Web(웹)의 등장

www, 월드 와이드 웹(World Wide Web)이란 인터넷에 연결된 사용자들이 서로의 정보를 공유할 수 있는 공간을 의미한다. 웹은 인터넷 상에서 텍스트나 그림, 소리, 영상 등과 같은 멀티미디어 정보를 하이퍼텍스트(hypertext) 방식으로 연결하여 제공한다. 웹은 HTML(Hyper Text Markup Language)이라는 언어를 이용해서 문서 작성이 가능한데, 이를 HTTP라는 프로토콜을 사용하면 누구나 검색하고 접근할 수 있다. HTML로 작성한 하이퍼텍스트 문서를 웹페이지(Web page)라고 부르고, 웹페이지를 관련된 내용으로 묶으면 웹 사이트(Web site)가 되고, 사용자가 웹 페이지를 검색하기 위해 사용하는 프로그램을 웹 브라우저(Web browser)라고 부른다.

단어
인터넷(International Network) TCP/IP을 기반으로 전세계의 네트워크를 하나로 연결하여 각각 PC가 가지고 있는 자료나 정보를 주고 받을 수 있는 광역 네트워크
TCP / IP 60년대 후반 부터 장비와 장비간에 통신을 위해 미 국방성에서 개발하여 만들어진 프로토콜로, 거의 모든 컴퓨터가 기본으로 제공하여 인터넷 표준 프로토콜. 4개의 계층적 구조로 계층마다 독립적이다.
World Wide Web 인터넷에 연결된 사용자들이 서로의 정보를 공유할 수 있는 공간
하이퍼텍스트(hypertext) 일반 텍스트와 달리 문장이나 단어 등이 링크를 통해 서로 연결된 네트워크처럼 구성된 문서
HTML 하이퍼텍스트(hypertext) 기능을 가진 문서를 만드는 언어
HTTP(Hyper Text Transfer protocol)  HTML 문서와 같은 리소스들을 가져올 수 있도록 해주는 프로토콜
Https(Hyper Text Transfer protocol Secure Socket)
HTTP에서 암호화 기능 추가
프로토콜(Protocol) 사람들이 공용 언어로 대화하듯이, 컴퓨터끼리 서로 이해할 수 있는 언어. 시스템 간의 통신을 원할하게 하기 위한 통신 규약 및 약속
Web page HTML로 작성한 하이퍼텍스트 문서
Web browser 사용자가 웹 페이지를 검색하기 위해 사용하는 프로그램 (ex. 크롬, 엣지)

Web은 전자 우편이나 파일을 주고받기 위해서 공통 공간을 만드는 일종의 정보 관리 시스템에서 시작되었다. 따라서 웹 1.0미리 분류하고 정리된 자료들만 일방적으로 전달받을 수 있었다. 하지만 웹 2.0에서는 사용자도 직접 정보를 생산하고 참여하는 집단 지성의 공간이 되었다. 오늘날의 web의 모습이다.

그렇다면 Web은 어떤식으로 연결될까?

Web(웹)의 연결

전세계는 TCP/IP 기반으로 광역 네트워크인 인터넷에 접속할 수 있다. 보이지 않는 네트워크는 www라는 가상의 공간에 사람들이 접속할 수 있게 하였다. 사람들은 HTML로 만들어진 하이퍼텍스트 문서를 만들고 이를 공유한다. 그렇다면 그 문서들에게는 어떻게 접속할 수 있을까? URL로 불리는 네트워크 상에서 자원이 어디에 있는지 알려주는 웹 주소를 통해 우리는 특정 문서에 접속할 수 있다.

특정 웹 페이지에 접속하기 위한 URL의 구조

1. 통신 프로토콜(communication protocol)
네트워크 상의 서버로 부터 웹 문서 정보(html)와 이미지 등의 리소스를 받아올 통신 방식을 미리 정해 놓은 것으로 HTTP, HTTPS, FTP, FILE, MAILTO 등이 있다.

2. 호스트 (Host Name)
네트워크 주소를 받아 네트워크에 연결해서 인터넷을 이용하기 위해 네트워크에 연결된 장치 또는 서버들을 호스트(Host)라고 한다. 그들에게 부여되는 고유한 이름인 호스트 명은 IP 주소나 MAC 주소와 같은 기계적인 이름을 대신하여 일반인이 쉽게 읽고 이해할 수 있는 이름으로 만들어진다.

네트워크 공간에 있는 모든 장치 노드(Node)라고 한다. 호스트(Host)는 네트워크 이용을 위해 네트워크 주소가 할당된 노드(Node)이다.
클라이언트(Client)네트워크상에서 요청을 하는 호스트(Host)이다.
서버(Server)요청에 응답할 수 있는 호스트(Host)이다.
결국 네트워크상에서 대부분 요청과 응답의 형태로 데이터가 오갈 때, 그 주체들이 바로 호스트(Host)인 것이다.

3~5. 도메인(Domain)
IP 주소는 네트워크 주소로, 웹에서 찾아가기 위한 주소이다. (192.168.0.1 과 같이 생겼다) IP는 사람이 이해하고 기억하기 어렵기 때문에 이를 위해서 각 ip에 이름을 부여할 수 있게 했는데, 이것을 도메인이라고 한다.

http://www.tistory.com 라고 입력하면 컴퓨터에게 "tistory.com"이라는 도메인을 하이퍼텍스트 형태로 받아와서 브라우저에 표기해달라고 말하는 것과 같다.

대부분의 도메인 네임은 DNS 서버에서 검색하는데, IP 주소를 인간이 기억하기 편한 언어체계로 변환해서 저장된 도메인 이름을 검색한다.

6. 포트번호(Port number)
클라이언트와 서버, 즉 호스트(Host)들이 데이터를 주고 받을 때, 실제로 데이터를 주고받는 것은 호스트 내에 있는 프로세스(process)들이다. 데이터가 호스트에 도착하고 나서도, 어떤 프로세스한테 가야하는지 알기 위해 호스트 내부의 프로세스 주소도 필요하다. 포트(port)는 프로세스의 논리 주소로, 호스트 내부의 주소이다.

소캣(socket)은 뭐야?

더보기

소캣(socket) 프로세스가 네트워크를 통해 데이터를 전달할 때 반드시 열어야하는 창구이다. 데이터 보내는 통로라고 생각하면 된다. 빨대처럼 양쪽이 뚫려있어야 하기 때문에 이쪽에서도 저쪽에서도 소캣을 열어야 정보를 주고 받을 수 있다. 소캣(socket)은 프로토콜(규약),IP주소,포트(Port) 넘버로 정의된다.

우리는 OSI 7계층을 나눠 네트워크 통신을 7단계로 나눈다. 나누는 이유는 7단계 중 특정한 곳에 문제가 생기면 해당 단계만 고치면 되기 때문이다. (OSI 7계층 단계 자세히 보기)

하지만 계층을 나누는 것만으로는 한계가 있어서 각 프로토콜을 일일히 정의할 필요없이 출입구만 열어주면 통신할 수 있는 소캣이 등장하게 된 것이다. 일반적으로 TCP/IP 프로토콜을 사용한다. TCP/IP출입구가 열려있는 상태로 상태값에 따라 양방향으로 정보를 주고받지만 HTTP단방향으로 데이터 요청이 있어야만 응답이 있다는 차이점이 있다.

 

7~8. 디렉토리 (directory)와 파일(file)

위 주소에서 HTTP는 단방향으로 데이터 요청이 있어야만 응답이 있는 프로토콜이다. 웹에서 브라우저는 URL 주소를 통해 웹페이지를 요청하고, 그 요청에 대해 웹 서버가 응답해준다. 디렉토리는 해당 자원이 웹 서버 내부의 어디에 있는지를 나타내는 경로이다. 예를 들어 만약 브라우저가 주소를 www.codns.com 에서 /codns 을 붙이면(요청), 웹서버는 codns 경로로 가서 해당 경로에 위치한 codns.jsp를 찾아서 클라이언트에게 응답해준다.

정적(Static) 웹페이지와 동적(Dynamic) 웹페이지

정적(Static) 웹 페이지웹 서버에 미리 저장된 파일(HTML 파일, 이미지, JavaScript 파일 등)이 그대로 전달되는 웹 페이지이다. 서버는 사용자가 요청에 해당하는 저장된 웹 페이지를 보내며, 사용자는 서버에 저장된 데이터가 변경되지 않는 한 고정된 웹 페이지를 보게 된다.

위키백과와 같은 데이터 교환만 필요할 때에는 정적 웹페이지로도 충분했을 것이다. 하지만 오늘날 우리는 클라이언트에 따라 내용이 다른, 보다 다양하고 최신의 필요한 정보들을 제공받기 위해 동적(Dynamic) 웹페이지가 필요해지게 된다.

동적(Dynamic) 웹페이지웹 서버에 있는 데이터들을 스크립트에 의해 가공처리한 후 생성되어 전달되는 웹 페이지이다. 서버는 사용자의 요청(Request)을 해석하여 데이터를 가공한 후 생성되는 웹 페이지를 보내고, 사용자는 상황, 시간, 요청 등에 따라 달라지는 웹 페이지를 보게 된다. 즉, 서버가 동적으로 문서를 만들어서 보내준다.

동적 웹 사이트는 정적 웹 사이트와 달리 서버 내부에서 추가적인 작업이 필요하기 때문에 서버 내부에 해당 작업을 처리하기 위한 모듈이 필요하다. 

▼ 동적 웹페이지의 종류

더보기
  • Client-side rendering (CSR)
    자바스크립트에 데이터를 포함해서 보낸 후, 클라이언트 쪽에서 HTML을 완성하는 방법.
    서버는 단지 JSON 파일만 보내주고, HTML은 JS가 그림 첫 페이지 로딩이 오래걸림.
    하지만 이후 유저와의 인터랙션이 빠름.
    봇 크롤러들이 JS는 읽지 못해서 SEO 문제가 발생.
    쿠키말고는 사용자 정보를 담을수 없음.

  • Server-side rendering (SSR)
    서버 쪽에서 템플릿 HTML에 데이터를 끼워넣어 완성된 형태의 HTML을 보내주는 방법.
    요청시마다 새로고침이 일어나며 서버에 새로운 요청을 전달.
    첫 페이지 로딩이 빠름, 이후 새 요청마다 새로고침이 되어 매우 비효율, 사용자에 대한 정보를 서버측 세션에 저장

  • 복합적인 방법
    클라이언트 쪽에서 Ajax 요청을 보내서 서버에서 데이터를 받아와 HTML을 완성하는 방법

 

동적(Dynamic) 웹페이지는 어떻게 만들 수 있을까? => WAS가 만들어준다.

웹 서버 (Web Server)

클라이언트가 요청한 정적인 컨텐츠를 HTTP 프로토콜을 통해서 제공해주는 서버. (정적인 컨텐츠를 제공하는 역할)
클라이언트가 동적인 컨텐츠를 요청할 경우, 웹 서버에서는 처리할 수 없으므로, 컨테이너로 보내주는 역할을 한다.
ex) Apache, NginX, IIS

컨테이너 (Container)

동적인 데이터들을 처리하여 정적인 페이지로 생성해주는 소프트웨어 모듈
웹 컨테이너 (Web Container) 혹은 서블릿 컨테이너 (Servlet Container)라고 불린다.
(서블렛(Servlet)이란 동적 웹 페이지에 사용되는 자바 기반의 웹 애플리케이션 프로그래밍 기술)

WAS (Web Application Server)

웹 서버로부터 오는 동적인 요청을 처리하는 서버, 웹 서버와 컨테이너를 합쳐둔 서버 (ex.Tomcat)

정적인 컨텐츠들은 웹 서버에서 해결 가능하므로 WAS를 거칠 필요가 없다.
따라서, 보통 웹 서버는 정적 컨텐츠, WAS는 동적 컨텐츠를 담당한다.
그렇지만, WAS 만을 사용하지는 않고 따로 웹 서버와 WAS를 분리하여 사용해준다. (보안, 데이터 처리, 서버 부하 등의 이유로)

서블릿(Servlet)

그렇다면 서블릿은 무엇일까?

서블릿(Servlet)은 서버에서 동적인 웹페이지를 만들기 위해 DB에서 원하는 정보를 가져올 수 있는 server app이 JAVA 언어로 쓰여져 있는 "웹서버 응용 프로그램"이다. 그리고 서블릿이 뭉쳐진 저장소를 서블릿 컨테이너라고 부른다.

예를 들어 회원목록을 달라고 했을 때, 서버 앱에서는 "list"라는 이름의 자바 코드를 실행한다.
이 코드를 서블릿이라고 했을 때, 서블릿은 최초로 요청시에 객체가 생성되고, 재사용 되기도 하며, 서버가 중지되면 삭제된다.

예시 : Apache와 Tomcat

Apache정적인 데이터를 처리하는 웹서버이고, Tomcat은 WAS 중에 하나로 동적인 처리를 하는 서블릿 컨테이너이다.

자바 개발 시 필요한 도구들을 JDK(Java Development Kit)라고 한다.
JDK의 일부인 JRE(Java Runtime Environment)는 자바 가상머신(JVM)의 실행환경을 구현한 도구이다. 런타임 환경은 프로그램 실행을 위해 클래스 파일을 로드하고 메모리 및 기타 시스템 리소스에 대한 액세스를 확보한다. 이를 위한 라이브러리나 환경파일들이 JRE에 포함되어 있다. 그래서 우리가 자바 프로그래밍을 할 때 JDK를 JAVA_HOME라는 약속한 이름의 경로에 두는거고, JRE를 라이브러리에 추가하는 것이다.

Tomcat도 WAS 종류이기 때문에 런타임 서버로 추가 등록한다. 그래서 이클립스 등의 IDE에서 서버 런타임에 톰캣을 등록하는 것. 이 때 포트번호가 겹치면 데이터를 전달하는 주소지(우편번호)가 겹쳐져 안될 수 있으니 안겹치게 설정해주어야 한다.

반응형
LIST
반응형
SMALL

Servlet

클라이언트 요청을 처리하고, 그 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍 기술. 즉, JAVA를 사용해서 웹을 만들기 위해 필요한 기술로, 자바 코드 안에 HTML 포함되어 있다. 클라이언트가 어떤 요청을 하면 그 결과를 다시 전송해주는 역할을 하는 JAVA 프로그램이다.

JSP

JavaServer Pages, HTML 코드에 JAVA 코드를 넣어 동적인 웹페이지를 생성하는 웹어플리케이션 도구. JSP가 실행되면 자바 서블릿(Servlet)으로 변환되며 웹 어플리케이션 서버(WAS)에서 동작되면서 필요한 기능을 수행하고 그렇게 생성된 데이터를 웹페이지와 함께 클라이언트로 응답한다.

서블릿 이전에 CGI가 있었다.

서블릿의 조상인 CGI(Common Gateway Interface)라는게 있다. CGI 이전의 웹서버는 단순히 사용자가 특정 경로를 입력하면 그 경로에 해당하는 리소스만 뿌려주었다. (주소 입력하면 정적인 페이지로 이동만 시켜줌) 그런데 CGI가 나오면서 사용자가 입력값을 인자로 넣은 프로그램을 실행시키면 그 결과를 웹으로 뿌려줄 수 있게 되었다. 바야흐로 동적인 페이지를 보여주기 위해 임의의 프로그램을 실행할 수 있는 기술의 탄생이다.

CGI 이전엔 경로->정적페이지 출력만 가능했는데,
CGI는 사용자에게 입력값을 받아 동적인 페이지를 보여줄 수 있게됨.

정적인 페이지는 예를들어 기업설명 페이지, 즉 사용자에 의해 변경될 일이 없으며 똑같 내용의 페이지를 말하고, 동적인 페이지는 SNS 페이지와 같이 사용자의 좋아요와 팔로우에 따라 알고리즘을 변경하여 사용자마다 다른 페이지를 보여주는 것을 말한다.

CGI 이전까지는 말 그대로 글자와 이미지 출력이 다였지만, CGI의 탄생으로 주소 하나에도 다양한 내용을 각자의 사용자에게 보여줄 수 있게 되었다.

CGI에서 서블릿으로

CGI는 웹서버에 요청이 들어오면 각각 처리한다. 일하는 인력 많고 처리를 하나씩 맡아서 한다.

CGI의 동작방식

CGI는 브라우저에서 웹서버에 요청이 갔을 때, 각각에 대한 처리 프로세스를 만들어낸다는 단점이 있었다. 그래서 대량의 트래픽을 처리하기에는 약간 무리가 있었다.

서블릿의 동작방식

서블릿도 CGI 규칙에 따라 데이터를 주고 받는 것은 같다. 하지만 서블릿은 각 요청에 대한 프로세스를 생성하는 것이 아니라, 서블릿 컨테이너로 보내서 처리하도록 했다.


서블릿 컨테이너는 요청이 들어오면 해당 요청을 처리할 일꾼 서블릿을 설정파일(가이드문서 같은거)을 읽어서 찾은 뒤, 어떤 서블릿이 필요한지 알았으면 해당 일꾼 서블릿을 찾는다. 또한 서블릿 인스턴스(클래스를 구체화한 제품)가 있다면 그 인스턴스를 가져와서 사용하고, 없으면 생성해서 그걸 이 일꾼 서블릿에게 가져다준다.


이 서블릿 인스턴스를 요청객체 HttpServletRequest와 응답 객체 HttpServletResponse에게 인자로 넘겨주면, 해당 일꾼 서블릿이 요청에 따른 로직을 처리하고, 처리 결과를 HttpServletResponse 객체에 담아 반환한다.(일꾼은 일을 끝냈음)


처리를 마치면 요청, 응답객체들은 사라지고 사용했던 서블릿 인스턴스만 남는다. 이 서블릿 인스턴스는 소멸하지 않고 있다가 다음에 같은 요청이 들어오면 서블릿 컨테이너가 다시 일꾼 서블릿에게 보내주면서 금방금방 일처리를 해준다.

 

서블릿 컨테이너는 서블릿의 생명주기를 관리하는 객체이다. 생성, 호출, 적절한 시점의 소멸을 담당한다.

 

그럼 한 요청을 처리하는 중에 또다른 요청이 들어오면 어떻게 될까? 그럼 멀티스레드로 요청이 처리되면서 일꾼 서블릿이 여러군데에서 호출되서 여러 스레드에서 사용된다. (이곳저곳 불려간다는 말임) 문제는 스레드 생성도 비용이 많이 들고, 다른 스레드로 전환하는 것도 부하가 걸리기 때문이다.

 

따라서 WAS는 이러한 문제를 처리하기 위해 프로세스 1개가 있고 그 내부에 스레드 풀이라는 스레드들이 생성될 수 있는 공간을 만들어 스레드로 처리했다.


스레드 풀은 스레드를 미리 생성해서 스레드가 필요할 때 꺼내쓰고 반납하는 저장소이다. 개수를 제한해서 일정 이상의 요청이 들어왔을 때는 대기하도록 만들어서 대량의 요청이 들어왔을 때도 조금 더 안정성이 증가했다.
그리고 사실 비슷한 경로에 요청을 한 클라이언트들의 비즈니스 로직은 대부분 중복되는 부분이므로, 스레드 사이에 있는 공유 자원 (Code, Data, Heap)을 통해 더욱 효율적인 처리가 가능했다.

 

 

▼ 스레드와 메모리에 관한 자세한 설명이 궁금하다면?

서블릿 개발 흐름

서블릿 라이프 사이클

서블릿 라이프 사이클

  1. 서블릿은 생성 이후에 init() 메소드를 통해 초기화된다.
  2. 클라이언트가 서비스(service())로 보낸 요청들을 처리한다.
  3. 서블릿은 사용 중지된 후, destroy()를 이용해 제거된다.

서블릿 컨테이너가 서블릿 클래스를 로딩하고, 인스턴스를 생성해 생성자와 함께 자바 서블릿 객체를 생성한다. 이 후 초기화와 사용자의 요청 비지니스 로직 처리(service), 완료 후 서블릿 상태 종료 및 소멸을 서블릿 컨테이너가 담당한다.

 

이 모든 과정을 컨테이너 내부에서 스레드 단위로 요청을 처리하는데, 이 과정을 개발자가 아닌 컨테이너가 제어하는 것을 IoC (Inversion of Control)라고 한다.

반응형
LIST
반응형
SMALL

객체지향 프로그래밍(Object-Oriented Programming)

좀 더 나은 프로그램을 만들기 위한 프로그래밍 패러다임으로, 로직을 상태(state)와 행위(behave)로 이루어진 객체로 만드는 것. 객체는 변수와 메소드를 그룹핑한 것이다. 

프로그래밍의 기본은 중복을 제거하는 것이다.덧셈 기능을 1000번 하는 것보다 "더하기"를 메소드로 만들면 코드 양도 줄어들고 문제가 발생해도 원인 파악이 쉽다. 입력값을 변수화 시키고 메소드들로 합계와 평균을 구하면 코드 양을 줄일 수 있다.

클래스

변수와 메소드가 많아지면 코드가 복잡해지게 된다. 따라서 연관되어 있는 변수와 메소드들을 함께 또 묶어서 "계산 기능"을 만든다. 이 로직들의 모임을 우리는 클래스(Class)라고 부른다.

클래스는 연관되어 있는 변수와 메소드의 집합이다.
class Calculator { // 중괄호로 영역을 표시한다. 계산 기능을 묶은 클래스
 	int left, right;
      
    public void setOprands(int left, int right){ // 변수
        this.left = left;
        this.right = right;
    }
      
    public void sum(){ //합계 내는 메소드
        System.out.println(this.left+this.right);
    }
      
    public void avg(){ //평균 내는 메소드
        System.out.println((this.left+this.right)/2);
    }
}

인스턴스

클래스는 일종의 설계도다. 클래스는 말 그대로 기능이 어떻게 동작하는지에 대한 설명이다. 이걸 사용하는 것은 new 라는 키워드와 함께한다. new Calculator()은 클래스 Calculator를 구체적인 제품으로 만드는 명령이다. 정확히는 클래스에 써있는 설계에 따라 복제본을 만들어서 복제한 클래스를 입맛대로 제품으로 만드는 것이다. 이렇게 만들어진 구체적인 제품을 인스턴스(instance)라고 부른다. 마치 데이터타입처럼, 사용자 정의의 데이터 타입의 Calculator를 만들었다고 생각하면 쉽다. 제품은 인스턴스, 설계도는 클래스 기억하기!

클래스가 구체적인 실체인 인스턴스가 되었을 때, 그것을 객체라고 부른다.

생성자

인스턴스가 생성될 때 호출되는 '인스턴스 초기화 메서드'이다. new 를 통해 인스턴스 생성 시에 실행해야할 초기 작업도 여기서 진행한다. 메소드처럼 클래스 내에 선언되지만 메소드와 달리 리턴값이 없다.(메소드는 리턴값이 없으면 void를 쓰지만 생성자는 그냥 아무것도 적지 않는다)

1. 생성자의 이름은 클래스의 이름과 같아야 한다.
2. 생성자는 리턴 값이 없다.

new는 인스턴스를 생성하고, 생성자는 인스턴스 변수들의 초기화에 사용된다. (초기값을 넣어줌)

모든 클래스에는 반드시 하나 이상의 생성자가 정의되어 있어야 한다. 사실, 원래 모든 클래스에는 하나씩 있어야하지만 그동안 클래스에 생성자를 정의하지 않아도 인스턴스 생성이 되었던 이유는 컴파일러가 제공하는 '기본생성자'가 있기 때문이다. 컴파일 할 때, 소스파일(*.java)의 클래스에 생성자가 하나도 정의되지 않은 경우,컴파일러는 자동적으로 아래와 같이 기본 생성자를 추가하여 컴파일 한다.

클래스 이름() { }
생성자() { } //자동으로 기본 생성자 추가

생성자는 초기에 주입할 필요한 값을 전달하거나 초기에 작업을 수행 할 때 사용하며, 만드는 방법은 클래스명과 동일한 메소드에 인스턴스에서 전달한 Argument(인수,인자)를 받을 수 있는 Parameter(매개변수)를 정의하면 된다.

Class 생성자 {
	int a ;
	public 생성자(int a) {
		this.a = a;
		...
	}

    생성자 foo = new 생성자(1) { //생성할 때 1을 보내서 a에 1이 들어감
        ...
    }
}

this

this는 클래스를 통해서 만들어진 인스턴스 자신을 가리킨다. "해당 객체의" 라는 뜻. Class가 인스턴스화 했을 때 그 인스턴스를 가르키는 특수한 문자.
Calculator c1 = new Calculator();
c1.setOprands(10, 20);
c1.sum();       
c1.avg();

c1은 Calculator 라는 클래스와 new가 만나 인스턴스가 되었고, 객체 되었다. c1은 setOprands 메소드를 호출해서 10과 20의 값을 던져준다. setOprands 안에는 변수 left, right가 있는데 이 변수들은 setOprands밖에 접근하지 못하기 때문. setOprands 내부에 있는 left와 right는 this 를 통해 밖에서 전달받은 값을 할당받을 수 있다. "해당 객체의" 멤버변수임을 표시해주는 것. 얘 우리 애야!

이러면 밖에서 뭘 넣어주느냐에 따라 left, right 값이 가지고 있는 것이 달라질 수 있다. 인스턴스의 멤버들이기 때문이다. 하나의 클래스를 여러개의 인스턴스로 만들어서 사용할 수 있다.

static

static을 맴버(변수,메소드) 앞에 붙이면 클래스의 맴버가 된다.
static double PI = 3.14;

π는 3.14로 다들 알고 있는 값이다. 이걸 일일히 인스턴스들이 가지고 있기에는 비효율적이다. 이 경우엔 변수를 클래스의 멤버로 만들면 모두가 공통으로 사용할 수 있다. 클래스의 멤버이기 때문에 가져다 쓸 때마다 인스턴스를 생성할 필요가 없다.(하나의 클래스에서 여러개의 인스턴스로 값 할당하는게 아니라 그냥 꺼내쓰는 클래스 내부에 있기 때문에) 따라서 클래스 변수는 변수의 변경사항이 있으면 빌려간 모든 인스턴스에도 값이 변경된다.

출처 : 생활코딩 Java

반응형
LIST
반응형
SMALL

1. 왜 JAVA 8을 사용하나?

1) Oracle 지원기간이 길다.

Oracle JDK 지원 기간이 다음과 같다.

Java 8 : 2030년 12월
Java 11 : 2026년 9월
Java 17 : 2029년 9월

옛날에 나온 Java 8이 그 이후 나온 11과 17보다 길다.

2) 자바는 객체지향형 프로그램이지만 JDK1.8부터 함수형 프로그래밍도 지원한다.

객체지향형 프로그래밍은 프로그램을 명령어의 목록으로 보는 것이 아니라 여러개의 독립된 단위(=객체)로 보기 시작하여 묶고, 재사용하고, 이리저리 만져서 조립하는 방법이라고 표현할 수 있다.

절차지향형 프로그래밍은 말 그대로 순서대로 진행하는 것이다.

함수형 프로그래밍은 순수한 함수를 사용해서 상태를 제어한다기 보다는 빨리 처리하는데 초점을 맞춘다. 실행 순서를 지정할 필요가 없기 때문에 비절차형 언어라고도 부른다. 외부에 영향을 받지 않아 동일한 입력값을 넣으면 항상 동일한 리턴값을 반환하는 함수 기능을 수행한다. 때문에 함수의 실행이 프로그램에 영향을 주지 않는다. 쉽게 말해 객체지향 프로그래밍은 객체들의 관계를 중심으로 긴밀한 관계성이 있어 상태에 따라 결과가 달라질 수 있지만, 함수형 프로그래밍은 그 자체로 처리만 해주기 때문에 각각의 동작들이 분리되어 있어 프로그램이 얼마나 오래 실행되고 있었는지 상관없이 같은 결과값을 도출해준다.(참조 투명성 – 값을 다시 할당하지 않는 것)

JDK 1.8은 2014년도에 출시되었고 다음과 같은 기능과 특징들이 있다.

람다식(Lambda expressions) - Stream
함수형 인터페이스 (Functional Interface)
디폴트 메서드 ( Default Method)
JVM의 변화
병렬 배열 정렬(Parallel Array Sorting)
컬렉션을 위한 대용량 데이터 처리 ( 스트림 )
Optional
Base64 인코딩과 디코딩을 위한 표준 API
새로운 날짜, 시간 API (Date & Time API

Java 8 을 기점으로 시대의 흐름에 맞게 병렬 프로세싱을 활용하고자 했고, 그로 인해 기존 버전에서는 구현하기 힘들었던 부분을 함수형 프로그래밍과 비동기 논블로킹 방식을 도입하여 해결했다. 

Java11은 기능추가가 된 것들이 많다. 그럼에도 불구하고 java8을 사용하는 이유는

1) 외부 개발 툴과의 연동성에서 가장 안정적이다. java11부터 요금정책이 바뀌어서 Oracle JDK 말고 Open JDK를 사용해야함.
2) Java11과 크게 차이가 나지 않는다. 따라서 java8 릴리즈 지원 안하면 그때 버전 업그레이드를 해도 됨.

2. JAVA 버전에 맞는 JDK 이름은?

원래는 Java SE 1.1, Java SE 1.2 같은 이름이다가 java 5부터 숫자로 붙여진다.
java SE 8 까지는 JDK 버전을 찍으면 JDK 1.8.x.x로 찍히는데 9버전부터는 그냥 JDK 9.x.x로 나온다.
따라서 Java 8 까지는 JDK1.8이라고 쓰지만, 9 이상은 JDK 9 로 쓴다.

자바 버전

java8 까지는 JRE와 JDK를 따로 다운로드 할 수 있도록 제공했다.

하지만 java9부터는 이런구분이 사라지고 항상 JDK를 다운로드하도록 변경되었다.

JDK의 디렉토리 구조도 변경되어 더이상 명시적인 JRE 폴더가 없다.

 

JRE(Java Runtime Environment) : JAVA 로만 개발할 때 사용되는 도구들 포함(JVM + java command-line tool)

JDK(Jaba Development Kit) : JRE + 컴파일러 + javadoc + javac 등등 기타 도구

 

반응형
LIST
반응형
SMALL
// 어노테이션을 이용한 URL 매핑
package java3_servlet_jsp;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class Nana extends HttpServlet{
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ServletException{
		
		//한글출력-> 유니코드로 바꿔주는것 : 유니코드가 아니면 깨진다.
		//response.setCharacterEncoding("UTF-8");
		//브라우저한테 내용을 UTF-8로 읽으라고 알려주는 것.
		response.setContentType("text/html; charset=UTF-8");
		
		PrintWriter out = response.getWriter();
		out.println("안녕! Hello!<br>안녕! Hello!");
	}	
}

 

@WebServlet("/hello") 처럼 어노테이션으로 URL 매핑이 가능하다.
단, web.xml 뿐만 아니라 어노테이션도 인식하려면 web.xml 상단의 <>에 metadata-complete="false"로 바꿔야한다.
"true"라는 것은 모든 매핑 데이터가 여기 web.xml에 있으니 여기서 참조하면 된다는 뜻이니까 false로 해야 다른곳도 찾는다.
원래 서블릿 2.x 버전에서는 web.xml에서만 매핑이 가능했으나 3.x버전부터는 둘 다 쓸 수 있게 되었다.

현재 web.xml 보니까 4.0 버전이네.

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 
id="WebApp_ID" version="4.0" >



어노테이션 매핑을 하면 
장점 : 코드 간결/편리성 / 프로젝트에서 서블릿을 나눠서 만들 경우에 어노테이션 쓰면 분리해서 하기가 쉽다.
 

하지만 브라우저마다 출력 방식이 다르기 때문에 그걸 맞춰서 해줘야한다. 예를들어 크롬은 <br>을 html이 아닌 텍스트로 인식한다.

안녕! 이렇게 치면 ??로 나온다. 한글은 1바이트로 표시할 수 없기 때문. 그럼 한글이 띄워지려면 어떻게 해야할까?

response.setCharacterEncoding("UTF-8");


이걸 추가해준다! 어? 근데 댐뀟 이렇게 나오네? 왜지? 인터넷 익스플로어에서는 우클릭>인코딩>유니코드(UTF-8)로 바꿔주면 잘 나온다.
그게 아니라면 이미 코드에 너가 지금 읽는게 한글이야~한글로 읽어~를 심어줘야한다.

response.setContentType("text/html; charset=UTF-8");


이러면 <br>태그를 전부 <br> 태그로 인식하고, 한글도 유니코드로 인식한다!

 JVM

JVM : 자바가상머신. 자바 바이트코드를 실행시키는 주체. 운영체제 종류와 무관하게 가능
즉, 운영체제 위에서 동작하는 프로세스로 자바를 컴파일해서 얻은 바이트코드를 기계어로 바꿔서 실행시키는 역할.

1. 소스코드 -> 바이트코드


소스코드는 .java로 저장한다.이걸 자바 컴파일러(javac)가 바이트코드로 바꿔주는데 그건 .class로 저장한다.
왜? 일단 1차적으로는 코드 숨기기, byte코드로 바꾸면 문법검사같은건 안하게 되면서 실행 시간이 단축됨.
근데 이러면 소스코드 변경할때마다 또 컴파일러가 .class로 byte코드로 변경하니까 번거로움.

2. 바이트코드 -> Runtime Data Area


이렇게 변경된 byte코드(.class)파일들은  class Loader가 Runtime Data Area로 로딩시킨다.
Runtime Data Area는 5가지 영역으로 되어있는데, 
1. 메소드영역 , 힙 영역 : 모든 스레드가 공유하는 영역
2. stack, PC Register, Native Method Stack : 스레드마다 하나씩 생성되는 공간
이렇게 나뉜다.

하나씩 보자.

1) method 영역


JVM이 시각될 때 생성되는 공간으로 byte코드(.class)가 여기에 저장된다.
그리고 모든 스레드가 공유하는 영역이니까 클래스의 정보, 변수 정보, static으로 선언한 공유변수가 저장되고 모든 스레드가 공유한다.

2) heap 영역


동적으로 생성된 객체가 저장되는 영역, 즉 new 연산으로 동적으로 생성된 인스턴스(클래스가 객체가 된 것)가 여기에 저장된다.
클래스의 객체, 배열 등 쉽게 소멸되지 않는 데이터가 있다.

heap 영역은 가비지 콜렉터(GC)의 영역이 된다. heap도 크게 3가지로 나뉘는데, young/old/permanent 이다.

2-1)GC(가비지 콜렉터)


가비지 콜렉터란 정리되지 않는 메모리, 유효하지 않는 메모리 주소로, 
예를 들어 첫 초기화 이후에 값을 또 할당했을 때 값이 덮어씌워지는데, 그 전에 선언했던 값이라던지
선언은 해서 메모리는 가지고 있는데 사용이 되지 않은 값이라던지를 자바에서는 garbage라 부른다.
메모리가 부족할 때 가비지를 메모리에서 해제시키고 공간만들어주는 것이 GC의 역할.
크게 Mark와 Sweep 과정으로 나뉘는데, 
Mark는 변수나 객체를 스캔하면서 어떤 객체 참조하는지 찾는 과정(=도달성(reacheable))이고(이때 스탑함),
Sweep는 Mark가 안된 객체를 힙에서 제거하는 과정이다.
GC가 Mark and Sweep를 거치며 가비지를 구분할 때 도달성(reachable)이라는 개념이 있는데, 
객체에 유효한 레퍼런스가 있는지(=객체를 참조하는지)를 말한다.

2-2)Stop The World


GC가 실행되려면 JVM이 애플리케이션 실행을 잠시 멈춰야한다. 그걸 Stop The World라고 한다.
멈추는 시간을 줄이는 것을 GC 튜닝이라고 한다.

2-3)heap 영역의 구조


Young 영역에서 발생한 GC를 Minor GC, old/permanent 영역에서 발생한 GC를 Major GC(Full GC)라고 한다.

쉽게 말해 young은 새롭게 생성된 객체가 위치해서 대부분 생성되었다가 사라지는 곳.
old는 reachable 상태가 유지되서 살아남은 객체들 모음. GC가 적게 발생함.
perm은 메소드랑 비슷하다. 클래스와 메소드 정보가 들어있는 곳.


3) Stack 영역


스택은 지역변수나 메서드의 매개변수, 임시 사용된 변수, 메서드의 정보가 저장되는 영역.
지역변수나 매개변수는 메소드가 호출이 종료되면 그 안에 있는 변수는 사라진다.
즉, 금방선언되고 금방 사라지는 애들이 여기 있다가 없어진다.

즉, class a(변수명) = new 생성자명(생성자 안에 들어갈 데이터);
여기서 a는 스택에 저장된다. 생성자명(데이터)는 heap 영역에 저장된다.
왜? 원래 자바의 레퍼런스 타입(클래스,인터페이스,배열,상수)들은 구조가 복잡하고 용량이 크다.
이것들까지 스택에 보관해서 그때그때 뽑아쓰면 비효율적이므로 heap에다가 저장 후, 
얘네들 주소를 참조하는 변수(a)를 스택에다가 저장해서 불러오는 것이다.

4) PC Register 영역


스레드가 어떤부분을 어떤 명령어로 수행할지 저장하는 공간.
스레드가 시작될 때 생성되며, 현재 수행되는 JVM 명령어 주소를 저장한다.

5) Native Method Stack 영역


자바를 제외하고 다른 언어,C언어나 C++언어가 실행되는 공간.
자바 프로그램이 컴파일 된 byte코드(.class)가 아니라 실제로 실행 가능한 기계어(0101)를 실행시키는 영역.



3. Runtime Data Area -> Execution Engine 영역 : 해석할 차례


로드된 클래스 파일의 byte코드를 실행하는 곳. 여기서 컴퓨터가 이해할 수 있는 기계어로 바꾼다.
방법은 두가지. 


1. 인터프리터 : 명령어 한줄한줄 해석하면서 실행. 2. JIT(just-in-time) 컴파일러 : 한줄한줄말고 런타임에 전부 한번에 실행.

여기서 해석한 것을 다시 Runtime Data Area로 가져가서 배치하고 스레드가 동기화되거나 가비지 컬렉션에 들어간다.


4. JNI(Java Native Interface) 영역


추가로 JNI는 JDK의 일부분인데, 다른 언어로 쓰여져있는 애플리케이션이나 라이브러리가 자바 가상머신과 상호작용을 할 수 있게 도와준다.
 

 

 


웹 서버 프로그램 구조


1. 클라이언트한테 요청을 받으면 서버가 DB에서 웹문서를 찾아본다. 있으면 그냥 바로 전달(정적인페이지 ex)로그인페이지 이동)
2. 원하는게 없다. 그러면 그걸 찾을 수 있는 서블릿 컨테이너 속 코드(서버 앱)를 찾는다. 
3. WAS가 자바 언어로 된 서블릿을 실행해서 동적인 페이지를 만든다.
4. 다시 클라이언트한테 응답한다.

----------------------------------------------------------------------------------------------

웹을 통해 통신하는 양 끝에는 클라이언트와 서버가 있다. 클라이언트는 요청자, 서버는 제공자(DB)이다.
클라이언트와 서버가 동기화가 되어야 두개가 동시에 변하는데, 서버는 하나라서 한번만 변하면 되지만 클라이언트는 여러명이므로 각각 업데이트 해야 한다.
예전에는 소프트웨어 업데이트가 자동 업데이트가 아니라 재설치의 개념이라 다른 프로그램 영향도 받고 해서 서버가 배포도 힘들고 클라이언트가 각각 업데이트도 힘들었었다.
그래서 웹이라는 것을 사용하게 된 것! 

일단 IP 주소는 네트워크 주소로, 웹에서 찾아가기 위한 주소이다. 
그리고 그 네트워크 주소를 받아서 네트워크에 연결해서 인터넷을 이용하기 위해 연결된 컴퓨터 또는 장치를 호스트라고 한다.
그리고 네트워크 공간에 있는 모든 장치를 노드라고 한다. 즉, 호스트는 네트워크 이용을 위해 네트워크 주소가 할당된 노드이다.
서버는 요청에 응답할 수 있는 호스트이다. 클라이언트는 네트워크상에서 요청을 하는 호스트이다.
결국 네트워크상에서 대부분 요청과 응답의 형태로 데이터가 오가는데 그 주체들이 호스트인 것.

실제로 데이터를 주고받는 것은 호스트 내에 있는 프로세스들인데, 이 프로세스는 프로그램,애플리케이션,소프트웨어 등등이 있다.
데이터는 호스트 안에 있는 프로세스들이 주고받기 때문에 호스트에 도착하고 나서도 프로세스를 찾아야한다.
따라서 호스트 내부의 프로세스 주소도 필요하다. 그게 포트(port)이다. 우편번호라고 생각하면 될듯.

소캣(socket)은 프로세스가 네트워크를 통해 데이터를 전달할 때 반드시 열어야하는 창구이다. (데이터 보내는 빨대같은 것)
즉, 이쪽에서도 저쪽에서도 소캣을 열어야 정보를 보내고 받는 것. 소캣은 프로토콜(규약),IP주소,포트넘버로 정의된다.
프로토콜 종류에 HTTP(인터넷에서 데이터 주고받을 수 있는 프로토콜,상태가 없어서 데이터 요청과 응답이 독립적으로 관리됨),TCP/IP(인터넷 통신망에서 정보 주고받는 기능을 이용한 프로토콜)이 있다.

HTTP는 웹이다. 웹에서는 이미 브라우저가 있어서 그걸 요청할 수 있는 환경을 갖춰져있고, 그 요청에 대해 웹서버가 요청을 응답해준다.
예를들어 만약 브라우저가 주소를 http://www.naver.com 에서 /login을 붙이면(요청) 웹서버가 페이지를 찾아서 로그인페이지를 응답해준다.

즉, 이 구조를 이용해서 우리가 문서에 글씨로 써서 컴퓨터에게 요청하면 컴퓨터 서버가 그걸 변환해서 엑셀로 돌려주는 것을 웹페이지 구조에 "얹어서" 사용하자는 것. 

왜 "얹어서" 사용하냐면, 웹페이지는 이미 정적으로 정해진 것들만 전달한다.(로그인페이지,웹툰페이지 등 주소 치면 딱 한장으로 나오는 정적 페이지)
하지만 우리는 업무를 위해서 사용한다. 예를들어 회원 목록, 정보리스트 등을 추출해서 응답받기를 원하는데, 그러려면 서버 단에서 그걸 변환해서 보내줘야한다.
즉, 클라이언트가 문서를 요청하면 서버단에서 동적으로 문서를 만들어서 사용자 목록을 만들어 응답해준다. 그걸 받기 위해 따로 클라이언트 프로그램을 만들 필요는 없다.
왜냐면 문서로 전달되니까, 그걸 브라우저로 받으면 되는거고, 대부분 윈도우에는 브라우저가 다 있다.
그러므로 우리가 만드는 것은 웹개발을 이용한 (요청의 답으로 동적인 문서를 만들어서 응답하는) 서버 프로그램인 것!

예전에는 웹개발자다 하면 서버프로그램을 만드는 개발자였는데 요즘은 클라이언트 단에서도 자바스크립트로 웹기반 클라이언트 프로그램을 만드는 사람도 생겼다.
그래서 웹서버, 백엔드 개발자 그리고 클라이언트, 프론트앤드 개발자가 생기게 된 것이다.

정적인 데이터가 아니라 동적인 데이터를 전달할 때, 우리는 한가지 기능이 더 필요하다.
예를들어 회원 리스트를 달라고 했다고 하자. com/member/list로 클라이언트 어플리케이션이 요청을 보냈다. 
과거방식이면 웹서버는 홈 디렉토리에서 있는지 찾아보고 찾아서 꺼내보면 웹문서 형태일 것이다. 그리고 그걸 그대로 전송해주었다.
근데 회원 목록이 문서로 미리 만들어져있는건 대체로 불가능하다. 데이터는 업데이트 되기 때문에 웹문서로 만들어져있다고 해도 원하는 정보가 아닐 가능성이 높다.
홈 디렉토리에 있는 것이 코드라고 해보자. 어떤 언어로 만들어져있던지 간에 그 코드가 있으면 DB에서 그 코드를 실행해서 찾을 수 있다.
이 코드를 Server app이라고 부른다.
즉, 그 코드를 클라이언트 어플리케이션에 돌려주는 것이 아니라,
그 코드를 실행하고, DB에서 찾아서, 받은것을 웹문서화해서 돌려받는 기능을 하는 무언가가 필요하다.
얘를 웹 어플리케이션 서버, WAS라고 한다. WAS에는 대표적으로 Tomcat이 있다.

즉, 우리는 서버단에서 클라이언트의 요청에 응답하기 위해 
1. 동적인 문서를 만드는 Sever app에게 요청하는 Web Server환경 
2. 서버 앱이 만든 문서를 실행하는 환경인 WAS(웹 어플리케이션 서버)환경이 필요하다.

그렇다면 서블릿은 무엇일까?
서블릿은 서버에서 동적인 웹페이지를 만들기 위해 DB에서 원하는 정보를 가져올 수 있는 서버 앱이 자바로 쓰여져 있는 "웹서버 응용 프로그램"이다.
예를 들어 회원목록을 달라고 했을 때, 서버 앱에서는 list라는 이름의 자바 코드를 실행한다.
이 코드를 서블릿이라고 했을 때, 서블릿은 최초로 요청시에 객체가 생성되고, 재사용 되기도 하며, 서버가 중지되면 삭제된다.
서블릿 : 자바로 쓰여진 동적인 움직임을 만드는 웹 서버 응용 프로그램. 이것들이 뭉쳐진 저장소를 서블릿 컨테이너라고 부른다.

Apache는 정적인 데이터를 처리하는 웹서버이고, Tomcat은 WAS중에 하나로 동적인 처리를 하는 서블릿 컨테이너이다.
자바 개발시 필요한 도구들을 JDK(Java Development Kit)라고 한다.
자바 가상머신(JVM)의 실행환경을 구현한 도구를 JRE(Java Runtime Environment)라고 한다. 라이브러리나 환경파일들이 있다.

그래서 우리가 자바 프로그래밍을 할 때 JDK를 JAVA_HOME라는 약속한 이름의 경로에 두는거고, JRE를 라이브러리에 추가하는 것이다.
톰캣도 WAS 종류이기 때문에 런타임 서버로 추가 등록한다.
또 포트번호가 겹칠수도 있다. 그러면 데이터를 전달하는 주소지(우편번호)가 겹쳐지기 때문에 안될 수 있으니 포트번호 잘 기억해둬야 한다.

 

 

 

Servlet

 

원래 IDE(통합 개발환경)을 쓰면 OS 상관없이 이렇게 안해도 쉽게 할 수 있다. 하지만 개별로 쪼개보자.

<서블릿 프로그램>
서블릿은 조각이기 때문에, 요청된 조각만 로드된다. 즉, list를 달라면 리스트에 해당하는 코드만 WAS에 의해 실행되고, 나머지는 실행되지 않는다.
서블릿 코드는 WAS에 의해 로드되고 실행되기 떄문에 클래스명은 상관이 없다. 중요한 것은 서블릿인지의 표시.
예를들어 약속되어있는 인터페이스명이거나, 추상클래스이거나. 추상클래스 형태로 서블릿을 참조한다.
서블릿을 참조한 추상클래스라면, 그 안에 있는 서비스(Service)라는 약속된 이름의 메인함수(메인이 붙지 않음. service라고 붙음)를 참조하게 된다.

예제)서블릿을 참조하는 추상클래스를 만들어서 안에 service라는 이름의 메소드를 가진 자바 코드를 만든다. 이걸 메모장에 붙여넣고
콘솔창에서 javac 이름.java 해서 실행하면 오류가 난다.왜?서블릿 라이브러리는 JDK에 포함이 안되어있기 때문에.
톰캣 폴더의 lib에 보면 servlet api 파일이 있다. 이걸 옵션으로 두고 자바를 실행하면 오류없이 실행된다. 그럼 그 폴더에 .class 파일이 생긴다!
-> javac -cp(라이브러리 읽을께) 서블릿 api 이름 java

자, 생성된 .class 파일은 보통 WEB_INF 안에 classes 폴더 안에 들어간다. 그럼 클라이언트가 주소를 줄 때 그 클래스를 콕 찝어서 요청하면 안되나?
ㅇㅇ 안된다. 왜냐면 WEB_INF는 클라이언트가 들여다볼 수도 없고 요청할 수도 없는 공간이기 때문. 즉, 비공개 공간이다.
홈 디렉토리 안에 있는 /nana.txt는 불러도 잘 실행된다. 하지만 WEB_INF는 안되는 것.
그럼 이걸 사용자가 요청하려면 어떻게 해야하나?
우리는 클라이언트가 요청하는 URL에 해당하는 서블릿 코드를 실행후 주기 위해 "매핑" 작업이 필요하다. 4를 달라고 하면 4로 매핑된 서블릿을 준다.
이걸 어디서 설정하냐? web.xml에서 설정한다.


우리는 지금 톰캣 자체의 root에서 실행한다. 도스창에서 실행하기 때문.
톰캣 들어가서 webapps>ROOT>WEB_INF>web.xml 파일이 있다. 여기에 이 서블릿 내용 붙여넣자.

서블릿 이름이 Nana.java이고 실행되어 classes 폴더 안에 Nana.class로 저장되어있을 때,
com/4 로 요청하면 그에 매핑된 클래스인 Nana class를 돌려준다.

<servlet>
<servlet-name>kosmo</servlet-name>
<servlet-class>패키지명.Nana</servlet-class> -> 패키지가 있으면 패키지명도 다 써줘야함.
</servlet>

<servlet-mapping>
<servlet-name>kosmo</servlet-name>
<url-pattern>/4 </url-pattern>
</servlet-mapping>
 

-> 가명을 설정해서 알아보는 느낌이라 생각하자. url 뒤에 붙은게 뭔지.
서버가 홈 디렉토리에 찾아봐도 같은 이름의 코드가 없으니 WAS로 넘겨서 매핑된게 있는지 찾아보고, 있으면 실행하는 것.(보안)
sysout 해도 서버의 콘솔에 실행된다. 그럼 클라이언트에게 다시 응답해주려면 어떻게 해야하나? -> 그게 response다.

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.*;

//여기 어노테이션 붙여서 할 수도 있는데 그건 다음 파일에서 보자.
//@WebServlet("/hello")	//서블릿을 참조하는 추상클래스
public class c_servlet extends HttpServlet{
							//http의 요청을 받는 도구     //응답을 주는 도구
	public void service(HttpServletRequest request, HttpServletResponse response)
			//예외
			throws IOException, ServletException{
			//원래 입출력은 Stream을 쓴다. 스트림의 기능들을 써보자.
				// 1. os라는 변수에 담을껀데, 우리 응답할꺼야.
				OutputStream os = response.getOutputStream();
				// 2. 대충 우리 응답하는데에 출력할꺼야.
				PrintStream out = new PrintStream(os, true);
				// 3. 이 문장을 출력해줘.
				out.println("Hello,Servlet!!");
	}
}


이러면 클라이언트 웹페이지에 Hello, Servlet

자바는 스트림이 있고 Writer 계열이 있다. 다국어(=한국어)면 Writer.
위에서는 Hello,Servlet이 영어라서 스트림 쓴것.

 

 

 

 

 

 

 

 

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 톰캣에서 가져온 web.xml이다. -->

<!--
 Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0"
  metadata-complete="false">

  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to Tomcat
  </description>
  
<!--   <servlet>
<servlet-name>na</servlet-name>
<servlet-class>java3_servlet_jsp.Nana</servlet-class> 패키지가 있으면 패키지명도 다 써줘야함.
</servlet>

<servlet-mapping>
<servlet-name>na</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping> -->

</web-app>

 

 

nana.java

// 어노테이션을 이용한 URL 매핑

package java3_servlet_jsp;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class Nana extends HttpServlet{
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ServletException{
		
		//한글출력-> 유니코드로 바꿔주는것 : 유니코드가 아니면 깨진다.
		//response.setCharacterEncoding("UTF-8");
		//브라우저한테 내용을 UTF-8로 읽으라고 알려주는 것.
		response.setContentType("text/html; charset=UTF-8");
		
		PrintWriter out = response.getWriter();
		out.println("안녕! Hello!<br>안녕! Hello!");
	}
}


@WebServlet("/hello") 처럼 어노테이션으로 URL 매핑이 가능하다.
단, web.xml 뿐만 아니라 어노테이션도 인식하려면 web.xml 상단의 <>에 metadata-complete="false"로 바꿔야한다.
"true"라는 것은 모든 매핑 데이터가 여기 web.xml에 있으니 여기서 참조하면 된다는 뜻이니까 false로 해야 다른곳도 찾는다.
원래 서블릿 2.x 버전에서는 web.xml에서만 매핑이 가능했으나 3.x버전부터는 둘 다 쓸 수 있게 되었다.

현재 web.xml 보니까 4.0 버전이네.
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
xmlns="http://xmlns.jcp.org/xml/ns/javaee
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd
id="WebApp_ID" version="4.0" >


어노테이션 매핑을 하면 
장점 : 코드 간결/편리성 / 프로젝트에서 서블릿을 나눠서 만들 경우에 어노테이션 쓰면 분리해서 하기가 쉽다.



하지만 브라우저마다 출력 방식이 다르기 때문에 그걸 맞춰서 해줘야한다. 예를들어 크롬은 <br>을 html이 아닌 텍스트로 인식한다.*/

안녕! 이렇게 치면 ??로 나온다. 한글은 1바이트로 표시할 수 없기 때문. 그럼 한글이 띄워지려면 어떻게 해야할까?

response.setCharacterEncoding("UTF-8"); 

이걸 추가해준다! 어? 근데 댐뀟 이렇게 나오네? 왜지? 인터넷 익스플로어에서는 우클릭>인코딩>유니코드(UTF-8)로 바꿔주면 잘 나온다.
그게 아니라면 이미 코드에 너가 지금 읽는게 한글이야~한글로 읽어~를 심어줘야한다.

response.setContentType("text/html; charset=UTF-8");

이러면 <br>태그를 전부 <br> 태그로 인식하고, 한글도 유니코드로 인식한다!

 

 

 

get과 post

클라이언트는 보통 문서를 요청한다.요청은 두가지가 있다. GET과 POST
이때 클라이언트는 요청하면서 무언가를 전달할 수 있다. 예를 들어 /hello?cnt=3 처럼 뒤에 붙이는 것.
이거는 추가적인 옵션을 전달하는 것. 단순한 정적인 /hello 페이지만 주는 것이 아니라 추가 옵션을 읽어서 그 옵션에 맞는것을 응답해줘야하는 것.
원래 /hello가 100번 출력할 때, 조건을 주면 3번만 나오는거다. cnt=3와 같은 조건을 QueryString이라고 한다.

package java3_servlet_jsp;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hi")
public class d_GET extends HttpServlet{
	@Override
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ServletException{
		
		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/html; charset=UTF-8"); //한글출력
		
		PrintWriter out = response.getWriter();
		
		int cnt = Integer.parseInt(request.getParameter("cnt"));
									//getParameter : 클라이언트와 약속된 용어가 이거다!를 표시. 무조건 문자열만 전달된다.
									//여기서 전달받는 것은 "3" 뿐이다. cnt= 라고만 되어있으면 빈 문자열, ?만 있으면 null인 것이다.
									//Integer.parseInt : 무조건 문자열만 전달되므로,3도 그냥 문자열이다. 따라서 숫자로 바꿔줘야한다. 
		//기본값 int cnt = 100;
		for(int i=0; i<cnt; i++) //cnt 횟수만큼 출력해라.
		out.println("안녕! Hello!<br>안녕! Hello!");
	}
}

// 근데 이렇게하면 실행했을 때 /hi로만 실행된다. 수동으로 ?cnt=3을 추가해줘야함.

//-------------------------------------------------------

 이걸 자동 적용을 위해, 기본값을 사용한다. int cnt = 100;
null이거나 빈 문자열이 발생해도 오류가 나지 않게 코드를 추가해주자!

String cnt_ = request.getParameter("cnt");
 
int cnt = 100;//기본값

//만약 cnt_ 문자열이 null이거나 비어있지 않으면 이걸 문자가 아니라 숫자로 바꿔주라.
if(cnt_ !=null && cnt_.equals(""))
cnt = Interger.ParsetInt(cnt_);

//그럼 null이거나 ""면 100번이 나오고, 그게 아니면 숫자로 바뀌어서 자동으로 된다.

for(int i=0; i<cnt; i++) //cnt 횟수만큼 출력해라.
out.println("안녕! Hello!<br>안녕! Hello!");


//근데 그렇다고 우리가 항상 주소창에 쓰냐?ㄴㄴ
//인덱스 페이지에 링크를 그렇게 걸어주면 된다.

<a href="java3_servlet_jsp/hi">100번 기본값</a>
<a href="java3_servlet_jsp/hi?cnt=3">3번만 나오는 예외값</a>

 

 

 

helloHtml.html

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>사용자 입력을 통한 GET 요청</title>
</head>
<body>
	<form action="hi">
	몇번 출력?
	<input type="text" name="cnt"/>
	<input type="submit" value="출력"/>
	</form>

	<!-- 입력하면 그 숫자만큼 자동으로 잘 출력된다! -->
</body>
</html>

 

Post로는?

//GET 방식은 단순한 조건을 뒤에 붙일 수 있다. 하지만 길어지면 보기가 힘들어지지 않을까?

package java3_servlet_jsp;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/notice_reg")
public class e_POST extends HttpServlet{
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ServletException{
		
		//한글설정
		response.setContentType("text/html; charset=UTF-8");
		//보내는것도 UTF-8로 인식해주라!
		request.setCharacterEncoding("UTF-8");
		
		PrintWriter out = response.getWriter(); //프린트해라.
		
		
		//title이랑 content라는 것을 요청받으면
		String title = request.getParameter("title");
		String content = request.getParameter("content");

		out.println("제목 :"+ title);
		out.println("내용 :"+ content); //그 내용 그대로 프린트 해.
		
	}
	
}

/* reg.html 실행했더니 어라?한글이 깨진다. 왜?
 * 이건 post하다가 생긴 문제이다. 왜냐면 톰캣은 기본적으로 ISO-8859-1 방식으로 인식해서 
 * 읽어들이기 때문에 그걸 다시 출력하니 에러가 난다.
 * 그럼 우리는 톰캣 서버로 가서 얘가 URLEncording="UTF-8"이라고 바꿔줘야할까?
 * ㄴㄴ 톰캣은 여러 페이지를 하나로 움직일 수 있기 때문에 잘 건들이지 않는다.
 * 나 혼자만 UTF-8로 하는게 일반적!
 * 우리 그러면 입력받기 전에, request도 인코딩을 바꿔주자.
 * 
*/

reg.html

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>사용자 입력을 통한 GET 요청</title>
</head>
<body>		<!-- 액션 연결은 e_POST의 @WebServlet("/notice_reg")로 간다. -->
	<form action="notice_reg" method="POST">
	제목 : <input type="text" name="title"/>
	내용 : <textarea name="content"></textarea>
	<input type="submit" value="출력"/>
	</form>

	<!-- <form action="notice_reg"> 이렇게만 출력하면 URL에 붙여서 전달된다.
		
		 method="GET"   : 없는거랑 동일하게 URL에 붙여서 전달한다.
		 method="POST"  : URL에 안붙이고 숨겨서 전달한다.
		
	
	-->
	
	
</body>
</html>
반응형
LIST
반응형
SMALL

+ Recent posts

반응형
LIST