스탠드언론 프로젝트 : 서블릿 컨테이너 자동으로 띄워줌

 

2. 빈 서블릿 컨테이너 띄우기

 

- 스프링부트 사용하지 않고 톰캣 띄우기

- 톰캣은 대표적인 서블릿

 

  • Tomcat Sublet Web Sever Factory

스프링 부트가 Tomcat Sublet 컨테이너를 내장해서 프로그램 코드로 쉽게 사용할 수 있게 만들어주는 도우미 클래스

 

TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
WebServer webServer = serverFactory.getWebServer();
  • .getWebServer();    진짜 웹 서버 우리 Sublet 컨테이너를 만드는 생성 함수
  • 톰캣 말고 다른걸 사용하고 싶을 경우 TomcatServletWebServerFactory 앞에 Tomcat 부분을 Jetty 등 사용하고 싶은걸로 적으면 동일하게 사용 가능
webServer.start();
  • Tomcat Sublet Container 동작

- 톰캣이 잘 떴는지 확인하는 방법

localhost 8080 시 404 뜸

 

 

3. 서블릿 등록

 

 

 

  • Mapping

Sublet 컨테이너가 웹 클라이언트로부터 요청을 받으면 여러개의 Sublet 중 어떤 Sublet에게 맡기면 될지 결정하는 작업

 

- 서블릿 등록

servletContext.addServlet("hello", new HttpServlet() {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ... }).addMapping("/*");
  • .addServlet                     - 서블릿 등록
  • .addMapping("/ 경로")    - 서블릿 만든 후 해당 경로로 들어올 경우 해당 서블리소가 맵핑해줘야함

 

- 웹 응답 3가지 필요

 

1)상태라인에서 상태 코드

resp.setStatus(200);

200 이 외 값을 설정하지 않는 다면 생략 가능

스프링에 enum 사용시 더 편리

 

2) 헤더

resp.setHeader("Content-Type","text/plain");

 

3)바디부분

resp.getWriter().println("Hello" + name);

 

 

-  프론트 컨트롤러

서블릿에 공통되는 부분들을 앞에 프론트컨트롤러라고 이름을 붙인 오브젝트에서 공통적인 작업함

 

 

1)프론트 컨트롤러로 변경

       servletContext.addServlet("frontController", new HttpServlet() {
           @Override
           protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
               // 인증, 보안, 다국어, 공통 기능
               // Sublet 컨테이너의 맵핑 기능을 front Controller가 담당
               // 3개 요청 method, path url, header body
               if(req.getRequestURI().equals("/hello") && req.getMethod().equals(HttpMethod.GET.name())){
                   String name = req.getParameter("name");
                   
                   resp.setStatus(HttpStatus.OK.value());
                   resp.setContentType(MediaType.TEXT_PLAIN_VALUE);
                   resp.getWriter().println("hello" + name);
               }
else if(req.getRequestURI().equals("/user")){
    //
}
               else{
                   //404
                   resp.setStatus(HttpStatus.NOT_FOUND.value());
               }


           }
           //frontController로 반을 경우 *으로 모두 받아야함
       }).addMapping("/*");    // 해당 경로로 들어올 경우 해당 서블릿과 맵핑 시킨다

helloController 에서 @GetMapping으로 했으므로 post로 /hello로 요청을 받으면 오류 뜸

 

 

-HelloController 사용해서 프론트 컨트롤러

WebServer webServer = serverFactory.getWebServer(servletContext ->  {
    //프론트 컨트롤러 분리 작업
    HelloController helloController = new HelloController();


    servletContext.addServlet("frontController", new HttpServlet() {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 인증, 보안, 다국어, 공통 기능
            // Sublet 컨테이너의 맵핑 기능을 front Controller가 담당
            // 3개 요청 method, path url, header body
            if(req.getRequestURI().equals("/hello") && req.getMethod().equals(HttpMethod.GET.name())){
                String name = req.getParameter("name");

                //bean 오브젝트 가져오기
                HelloController helloController =  applicationContext.getBean(HelloController.class);

                //프론트 컨트롤러 분리 작업
                //추출된 파라미터를 메소드를 호출하는데서 사용하고
                // ret으로 결과값 리턴
                String ret = helloController.hello(name);

                resp.setStatus(HttpStatus.OK.value());
                resp.setContentType(MediaType.TEXT_PLAIN_VALUE);
                resp.getWriter().println(ret);
            }
            else{
                //404
                resp.setStatus(HttpStatus.NOT_FOUND.value());
            }


        }
        //frontController로 반을 경우 *으로 모두 받아야함
    }).addMapping("/*");    // 해당 경로로 들어올 경우 해당 서블릿과 맵핑 시킨다

 

여기까지 스프링 부트는 사용하지 않음

 

HelloController.java

 

@GetMapping("/xxx")

해당 /xxx 경로로 들어오는 요청을 받아서 return 해줌

 

@RestController

웹 응답이 만들어질 때 이 컨트롤러 메소드의 return type인 저 스트링을 보고

content type 자동으로 결정해줌

스트링이 return 되는 경우 텍스트 슬래시 플레이 이타입의 컨텐츠 타입이 만들어지고

리턴한 저 문자열이 그대로 응답의 바디에 들어감

 

 

Tomcat

자바 서블릿의 컨테이너

 

 

 

 

 

'SpringBoot > 프로젝트' 카테고리의 다른 글

자동 구성 정보 대체하기  (0) 2023.11.30
@Conditional 학습 테스트  (0) 2023.11.30
[Spring Boot] jetty 서버 구성 추가하기  (0) 2023.11.29
Test Code 작성  (0) 2023.11.27
DI를 이용한 Decorator  (2) 2023.11.27

익명 클래스

  • 이름 없는 일회용 클래스
  • 클래스 정의와 생성을 동시에 

 

익명클래스는 본인의 클래스 이름이 없으므로, 상속받을 부모클래스 또는 인터페이스에 대해서는 어딘가에 명시 필요

new 연산자로 객체 생성과 동시에 {  } 안에 클래스 내용을 정의합니다.

// 부모 클래스
class Animal{
    public String cry(){
        return "동물이 운다";
    }
}

// 자식 클래스
class Dog extends Animal{
    @Override
    public String cry(){
        return "개가 짖는다";
    }
}

public class Main{
    public void main(String[] args){
        Animal a = new Dog();
        a.cry();
    }
}

 

1) 익명 클래스 생성

위의 코드를 익명클래스 변경한다면

아래와 같이 객체를 생성하지 않고 부모 클래스의 이름을 적은 후 클래스 내용 작성

 

// 부모 클래스
class Animal{
    public String cry(){
        return "동물이 운다";
    }
}


public class Main {
    public static void main(String[] args) {
        Animal dog = new Animal() {
            @Override
            public String cry() {
                run();      // 새로 정의한 메소드로 내부에서만 사용 가능
                System.out.println("개가 짖는다");
                return "개가 짖는다";
            }

            public void run() {
                //return "개가 달린다";
                System.out.println("개가 달린다");
            }

        };


        System.out.println(dog.cry());
        dog.cry();
        //dog.run();    // 오류 발생 ! - 외부에서 호출 불가능

    }

}

 

2) 익명 클래스 사용 시 주의 사항

  • 익명 클래스 방식으로 선언한다면 오버라이딩 한 메소드 사용만 가능
  • 새로 정의한 메소드는 외부에서 사용이 불가하고 익명 클래스 내부에서만 사용 가능
  • 예제에서 새로 정의한 메소드인 run은 외부에서 사용이 불가하며 내부에서만 동작

 

3) 그 외 

해당 코드를 돌리면 아래의 결과가 나오는데 내 생각에서는

'개가 달린다 개가 짖는다 개가 달린다 개가 짖는다'가 나와야하지 않을까 생각을 한다.

 

이유는

run(); 개가 달린다  -> sysout 개가 짖는다

-> dog.cry(); 실행  cry 메소드 안에서 새로 정의한 run 메소드를 불러 개가 달린다 -> sysout 개가 짖는다

라고 생각하는데 dog.cry(); 실행 시 '개가 달린다'는 찍히지 않고 ' 개가 짖는다'만 찍힌다.

dog.cry();  외부에서 실행하였지만 cry 내부에 있는 run은 실행되어야하는거 아닐까 ? 오류도 발생하지 않는다

 

<결과 값>

개가 달린다
개가 짖는다
개가 짖는다

 

 

람다

  • 익명 메소드만 전달, 인터페이스를 구현한 익명 클래스의 인터페이스 생성 방법
  • 익명 클래스를 람다로 변경하면 훨씬 간결

 

익명 클래스와 람다식 차이

1. 익명 클래스 : 새로운 클래스 생성 / 람다 : 새로운 메서드 생성

2.익명 클래스 this : 새로 생성된 클래스 / 람다 : 람다식 포함 클래스

익명 클래스는 새로운 클래스를 생성하기 때믄에 this는 해당 클래스 가리킨다

새로운 클래스를 만드는게 아니고 그냥 메서드 만다는 람다는, 메서드 즉 람다가 있는 클래스를 가르킨다

 

 

 

 

 

 

 

우선,

@Controller와 @RestController 둘 다 spring에서 controller를 지정하기 위한 어노테이션이다

 

 

@Controller

Spring MVC의 Controller

View 반환

 

<과정>

1) Client에서 보낸 요청은 DispatcherServlet을 거쳐 HandleMapping을 통해 Controller 찾고 요청 수행

2) Controller는 받은 요청을 처리하고 난 뒤 ViewName 반환

3) DispatcherServlet은 ViewReslver를 통해 ViewName에 해당하는 View를 찾아 사용자에게 반

 

<but Date 반환하고 싶을때>

ResponseEnity의 Body를 사용해야하는데, 이 때 @Controller와 함께 @ResponseBody 어노테이션 사용하면

JSON 형태의 데이터 반환 가능

ResponseEnity로 감싸서 객체 반

 

 

@RestController

RESTful웹 서비스의 Controller

간단하게 말하자면 @Controller + @RequestBody 합쳐진 어노테이션

JSON 형태의 객체 데이터 반환

ResponseEntity로 감싸서 반환

 

 

+ Recent posts