programming study/B-Spring

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 (1)

gu9gu 2022. 11. 22. 18:54

목록

웹서버 (Web Server)

웹 어플리케이션 서버 (WAS, Web Application Server)

웹서버, WAS 구성 방법

서블릿

서블릿 컨테이너

서블릿 컨테이너의 동시 요청을 위한 Multi Thread 처리

쓰레드 풀

백엔드 개발자로서 해야 할 것 ( 생각해보면 좋은 내용 ) : SSR 기술, 서버 요청 종류

자바 웹 기술 : Spring boot, Spring MVC, Thymeleaf가 요즘 많이 사용되기 때문에 주로 학습

서블릿 사용하기

http요청에따른 스프링 동작 흐름

HttpRequestServlet 역할

HTTP 요청 메세지를 통해 클라이언트에서 서버로 전달하는 방법 3가지

HttpServletResponse - 기본 사용법

MVC 패턴이란?

실습(서블릿 등록 방법, jsp)

 

 

 

 

 



본론

 

웹서버 (Web Server)

HTTP 기반으로 동작하는 정적 리소르(HTML, CSS, JS, 이미지, 영상)를 제공해주는 server

• ex) NGINX, APACHE

 

웹 어플리케이션 서버 (WAS, Web Application Server)

HTTP 기반으로 동작하고 정적 리소스를 제공하는 Web Server의 기능을 하고 어플리케이션을 동작시키는 기능도 있는 Server입니다.

 ex) Tomcat

 

웹서버, WAS 구성 방법

WAS는 WAS와 DB만으로 시스템을 구성할 수 있습니다. api 서버로서의 역할만 하여 데이터를 보내주는 역할을 합니다.

WAS는 개발자에 의해 만들어진 로직을 수행하기 때문에 오류가 발생할 수 있고 로직을 수행하고 DB와 통신을 하는 등의 어플리케이션 동작으로 과부하가 발생할 수 있습니다. 따라서 정적 리소소는 웹서버에서만 관리하게 하여 
클라이언트 -  웹서버 - WAS - DB 구조로 구성하면 과부하를 방지할 수 있고 WAS에서 오류가 발생했을 때 웹서버에서 오류 화면을 띄우기도 편합니다.


서블릿

서블릿은 웹 통신의 요청과 응답에 대해 처리 하는 기술이고 자바에서는 일반적으로 HttpServlet 클래스를 상속받아 servlet 객체로 만듭니다.

 

서블릿 컨테이너

Tomcat, Jetty 같이 Servlet을 지원하는 WAS를 서블릿 엔진(=서블릿 컨테이너)라고 합니다.

서블릿 컨테이너는 서블릿의 생명주기를 관리합니다.

서블릿 컨테이너는 HttpServlet 객체를 상속 받은 서블릿 객체는 싱글톤으로 생성합니다.

서블릿 컨테이너는 동시 요청을 위한 Multi Thread 처리를 지원합니다. 개발자가 직접 멀티 쓰레드 기능을 구현하지 않아도 되고 싱글 쓰레드인 듯 개발이 가능해집니다. 단 멀티쓰레드 환경이므로 싱글톤 빈을 주의하여 사용해야합니다.

서블릿 컨테이너는 http 메세지를 분석해서 사용하기 쉽게 HttpServletResponse, HttpServletRequest 객체를 생성합니다.

서블릿 컨테이너는 웹 서버와 소켓을 만들어 통신합니다.

서블릿 컨테이너는 JSP(Java Server Page)와 Servlet이 작동할 수 있는 환경을 제공합니다.

참고 : 서블릿 컨테이너와 WAS 관계

 

서블릿 컨테이너의 동시 요청을 위한 Multi Thread 처리

 - Thread란? 

   어플리케이션 코드를 하나하나 순차적으로 실행하는 흐름이고 프로세스(실행중인 프로그램)의 단위입니다.

 

  - Multi Thread 처리 과정

  • 서블릿 컨테이너는 요청이 올 때 마다 새로운 자바 쓰레드를 하나 생성
  • HTTP 서비스 메소드를 실행하고 나면, 쓰레드는 자동으로 소멸

  - Multi Thread 장점

  • 동시 요청이 가능해집니다.
  • 리소스(CPU, 메모리)가 허용하는 범위에서 처리 가능합니다.
  • 하나의 쓰레드가 지연되어도 나머지 쓰레드는 정상 동작합니다.

  - Multi Thread 단점

  • 쓰레드는 리소스를 많이 사용해서 동시 요청이 오는 경우 응답 속도가 느려집니다.
  • 멀티 쓰레드 사용시 쓰레드 컨텍스트 스위칭(CPU가 제한적이여서 CPU가 다음 쓰레드를 처리하려고 변경하는 것) 하는데 리소스를 사용합니다.
  • 쓰레드 생성에 제한이 없는데, 요청이 너무 많이 와서 CPU와 메모리의 한계를 넘으면 서버가 죽을 수 있습니다.

쓰레드 풀

  - 정의 및 특징

  • 쓰레드 생성에 제한이 없어서 서버가 죽을 수 있는 문제를 해결하기 위한 기술
  • 갯수를 설정해서 쓰레드 풀에 쓰레드를 미리 생성해둘 수 있습니다. Tomcat에서 쓰레드 수 기본값은 200입니다.
  • 서블릿 컨테이너가 쓰레드 풀에 있는 쓰레드를 꺼내서 사용하고 사용이 끝났으면 쓰레드 풀에 반납합니다.
  • 동시 요청으로 인해 생성해둔 쓰레드를 모두 사용하는 경우에는 나머지 요청에 대해서 거절하거나 특정 숫자만큼만 대기하게 설정할 수 있습니다.

  - 장점

  • 쓰레드를 미리 생성해둬서 쓰레드 생성/종료에 사용되는 리소스가 줄어들고 응답시간이 빠릅니다.
  • 쓰레드 생성 수를 설정할 수 있어서 많은 동시 요청에 대해서 안전한 처리가 가능합니다.

  - 실무 팁

  • WAS의 주요 튜닝 포인트는 Max Thread 수입니다.
  • Thread 수를 너무 낮게 설정하면 CPU,메모리에는 부하가 발생하지 않지만 응답 지연으로 인해 문제가 발생됩니다.
  • Thread 수를 너무 높게 잡으면 CPU, 메모리에 부하가 발생하여 서버가 다운될 수 있습니다.
  • 많은 요청으로 인한 장애가 발생하면 클라우드 서버인 경우 일단 서버(Instance) 수를 늘리고 추가적인 튜닝을 합니다. 클라우드 서버가 아닌 경우 평소에 튜닝을 해둬야 합니다.
  • Thread 수의 적절한 수는 상황마다 달라서 항상 실제 서비스에 반영하기 전에 성능 테스트를 해야합니다.
    (사용 툴 : 아파치 ab, 제이미터, nGrinder )

참고

서블릿과 스프링,스프링부트 : https://12bme.tistory.com/555

 


백엔드 개발자로서 해야 할 것 ( 생각해보면 좋은 내용 ) : SSR 기술, 서버 요청 종류

 

SSR (Server Side Rendering)

 - 서버에서 최종 HTML을 생성해서 클라이언트에 전달하는 기술 ex) JSP, Thymeleaf ( Thymeleaf vs JSP (velog.io) )

 - 정적이고 복잡하지 않은 화면을 주로 만든다.

CSR (Client Side Rendering)

 - 웹 프론트 앤드 개발자가 사용하는 기술이기 때문에 백엔드 개발자로서 이것 까지 학습하기에는 벅차다. ex) React.js, Vue.js

 

서버 요청 종류

1. 웹브라우정적 Resource 요청 ( ex) HTML, CSS, JS 파일, 이미지, 영상 )

2. 웹브라우저동적HTML 파일 요청

 1) WAS에 요청

 2) WAS가 DB에 정보 조회

 3) JSP or Thymeleaf 를 사용해서 동적인 HTML 문서 생성하여 반환
3. 웹브라우저 or 앱, 서버DATA 요청 :데이터만 주고 받음, UI화면이 필요한 경우 클라이언트에서 별도 처리, 주로 JSON 형식으로 반환

 


자바 웹 기술 : Spring boot, Spring MVC, Thymeleaf가 요즘 많이 사용되기 때문에 주로 학습


배포 방법 
Spring : 소스는 War 파일로 만들고 서버에 was(ex) Tomcat)를 직접 설치한 다음 Was에 war파일을 배포

Spring Boot: 소스 빌드 결과 Jar 파일에 서버를 포함시켜서 간단하게 배포 가능

                    ( java가 설치된 아무 서버에서나 실행 가능, "java -jar 파일명" 로 간단하게 실행 )

 * war : jsp를 사용할 때, tomcat 서버를 따로 둘 때 war Packaging 방법을 사용한다.

 * "spring web" dependency추가 : 내장톰켓을 사용하기 위한 의존성 추가

 

웹 기술

Web Servlet - Spring MVC

Web Reactive - Spring WebFlux ( netty 웹프레임워크 같이 사용 )

 

자바 뷰 템플릿 ( HTML을 편리하게 동적으로 생성하는 뷰 기능 )

JSP - 속도 느림, 기능 부족

프리마커(Freemarker), 벨로시티(Velocity ) - 속도 문제 해결, 다양한 기능 but 발전이 없음

타임리프(Thymeleaf) 

 -내추럴 템플릿 : HTML의 모양을 유지하면서 뷰 템플릿을 적용하기 때문에 타임리프 파일을 브라우져에서 열었을 때 어느정도 확인 가능, (jsp는 코드만 보임)

 -스프링 MVC와 기능 통합이 가능해서 타임리프를 주로 사용함 (단 성능은 프리마커나 벨로시티가 더 빠르나 문제 될정도는 아님)

 


서블릿 사용하기

서블릿을 등록시키기 위한 어노테이션

@ServletComponentScan // 스프링이 자동으로 하위 패키지들에서 서블릿을 찾아서 등록해준다.(내장 서버를 가지고 있는 경우 사용 가능)

                                             // @SpringBootApplication 위에 설정해준다.

 

서블릿으로 만들기 위한 어노테이션

@WebServlet(name="", urlPatterns = "")  // name : 서블릿 이름, urlPatterns : url 매핑

                                                                     // HTTP 요청을 통해  매핑된 url이 호출되면 서블릿 컨테이너가 service 메서드를 호출합니다.

protected void service(HttpServletRequest request, HttpServletResponse response)

 

 

servlet 생성 및 url 요청시 servlet container 역할

  servlet 생성 과정

    1.스프링부트가 내장 Tomcat 서버를 띄워준다.

    2.Tomcat으 servlet container 기능을 할 수 있고 servlet container가 servlet을 생성해서 가지고 있습니다.

  url 요청 처리 과정

    1. url 창에 요청한다.
    2. 브라우져가 http 메세지를 만들어서 웹서버로 보낸다.

        브라우져 -> WEB Server -> WAS 의 WEB Server -> servlet container(Tomcat)
    3. servlet container 가 request, response 객체를 만들어서 작업을 처리하고 반환한다. 

    4. was 에서 response객체를 가지고 http response 메세지를 만들어서 브라우져로 반환한다.

 


HttpRequestServlet 역할

 1. HTTP 요청 메세지를 편리하게 사용할 수 있도록 서블릿이 HTTP 요청 메세지를 파싱하여 그 결과를 HttpRequestServlet 객체에 담아서 제공한다.

 참고)  HTTP 요청 메세지 - Content-Type : application/x-www-form-lencoded ->  form 태그에 의한 요청

 

 2. 임시 저장소 기능

   - 해당 HTTP 요청이 반환될 때까지 유지되는 임시저장소 기능

    저장 : request.setAttribute(name, value)

    조회 : request.getAttribute(name)

 

3. 세션 관리 기능

    request.getSession(create : true)    ????

 

4. body 정보를 꺼내서 사용

    request.getParameter(name)

 


HTTP 요청 메세지를 통해 클라이언트에서 서버로 전달하는 방법 3가지

 

1. GET - 쿼리 파라미터

 /url?username=kim&age=21

content-type : null

 메세지 바디 없이, url의 쿼리 파라미터에 데이터 포함해서 전달

 ex) 검색, 필터, 페이징

 

2. POST - HTML Form

 content-type : application/x-www-form-urlencoded

 메세지 바디에 쿼리 파라미터 형식으로 전달 username=kim&age=21

 ex) 회원가입, 상품 주문

 

"GET - 쿼리 파라미터" 방식과 "POST-HTML form" 방식에서 사용하는 값 가져오는 법

  • request.getParameterNames().asIterator().forEachRemaining(paramName -> System.out.prlintln( paramName + " : " + request.getParameter(paramName);                          // 모든 키, 값 가져오기
  • String username = request.getParameter("키네임");  // 키네임으로 값가져오기
  • String[] dupliUsername = request.getParameterValues("키네임");  // 키네임이 중복될 때 모두 가져오기

 

3. HTTP message body

 HTTP API에서 주로 사용

 데이터 형식으로 JSON, XML, TEXT 사용. JSON을 주로 사용

 POST, PUT, PATCH 

 

1. 단순 text 보내기

http-method : post

content-type : test/plain

postman에서 http 요청 보내기

ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);

 

2. json 보내기

http-method : post

content-type : application/json

ObjectMapper 와 모델을 사용해서 json 데이터 맵핑

postman 에서 http 요청 보내기

 

@WebServlet(name="requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {
    /*
     * JSON 결과를 파싱해서 사용할 수 있는 자바 객체로 변환하려면 Jackson, Gson 같은 JSON 변환
     * 라이브러리를 추가해서 사용해야 한다. 스프링 부트에서는Jackson라이브러리( ObjectMapper )를 제공한다.
     */
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        System.out.println("messageBody = " + messageBody);

        HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
        System.out.println("helloData.getUsername() = " + helloData.getUsername());
        System.out.println("helloData.getAge() = " + helloData.getAge());

        response.getWriter().write("ok");
    }
}

 


HttpServletResponse - 기본 사용법

Content - ContentType, CharacterEncoding, ContentLength
Cookie(name,value, MaxAge)
redirect (Status, Header)

 

 

Http 응답 데이터 - 단순 텍스트, HTML, API JSON

 

단순 텍스트

response.setContentType("text/plain");

response.setCharacterEncoding("utf-8");

response.getWriter().println("텍스트");

 

HTML

response.setContentType("text/plain");

response.setCharacterEncoding("utf-8");

PrintWriter writer = response.getWriter();

writer.println("<html>");

.

,

writer..println("</html>");

 

API JSON

private ObjectMapper objectMapper = new ObjectMapper();

@Override

protected Service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

   response.setContentType("application/plain");

   response.setCharacterEncoding("utf-8");

 

   HelloData helloData = new HelloData();
   helloData.setUsername("kim");
   helloData.setAge(21);

 

   String result = objectMapper.writeValueAsString(HelloData);

   response.getWriter().write(result);
}


MVC 패턴이란?

사용배경

서블릿만 사용하면 자바코드에 뷰 화면 만드는 HTML 코드가 섞여서 지저분

JSP 파일을 사용하여 HTML 코드를 JSP파일에서 둘 수 있지만 JSP 파일 중간중간 동적으로 변경이 필요한 자바코드를  사용해야 해서 지저분

한 파일에 뷰와 비지니스 로직이 다 있으면 한 파일을 가지고 계속 수정해야 해서 유지보수에 좋지 않음

MVC 패턴을 사용해서 해결해보자

 

Model View Controller

Controller : HTTP 요청을 받아 파라미터를 검증하고 비니니스 로직을 수행( 보통 비니지스 로직은 service 로 따로 분리하여 service를 호출한다.) View에 전달한 데이터를 Model에 담는다.

Model : Controller에서 받은 데이터를 View로 전달한다. Model 덕분에 View는 비지니스 로직, 데이터를 가져오는 로직에 관여하지 않고 렌더링에만 집중할 수 있다.

View : Model에서 데이터를 받아 화면을 렌더링 한다. HTML을 생성하는 것

 

실제 작업시 

Controller는 servlet으로 구현

View은 JSP으로 구현

Model은 HttpServletRequest 객체 내부에 있는 데이터 저장소 사용. request.setAttribute(), request.getAttribute() 

 

/WEB-INF

WAS (Web Application Server)의 규칙으로

/WEB-INF/... 이 경로안에 JSP가 있으면 외부에서 직접 JSP를 호출할 수 없다. 우리가 기대하는 것은 항상 컨트롤러를 통해서 JSP를 호출하는 것이다.

 

redirect vs forward

리다이렉트는 실제 클라이언트(웹 브라우저)에 응답이 나갔다가, 클라이언트가 redirect 경로로 다시 요청한다. 따라서 클라이언트가 인지할 수 있고, URL 경로도 실제로 변경된다. 반면에 포워드는 서버 내부에서 일어나는 호출이기 때문에 클라이언트가 전혀 인지하지 못한다

response.sendRedirect("/basic/hello-form.html");

            vs

String viewPath = "/WEB-INF/views/save-result.jsp";

RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);

dispatcher.forward(request, response);

 

 

단순 mvc 패턴은 controller에서 공통적인 로직이 많다. 코드를 줄이기 위해 프론트 컨트롤러 패턴을 사용해보려고 한다.

프론트 컨트롤러패턴은 궁극적으로 스프링 mvc 패턴과 유사하다.


프론트 컨트롤러 패턴

프론트 컨트롤러 : 단순 MVC 패턴에서 각 컨트롤러가 받던 요청을 한 곳에서 받은 후 각 컨트롤러로 뿌려주는 역할

 

특징

 - 프론트 컨트롤러 서블릿 하나로 클라이언트의 모든 요청을 받음

 - 프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출

 - 입구가 하나여서 공통 처리가 편해지고 나머지는 servlet을 사용하지 않아도 됨

 - 스프링 웹 MVC 패턴의 DispatcherServlet이 프론트 컨트롤러 패턴으로 구현되어 있음

 - 프론트 컨트롤러는 인터페이스다

 

동작

 http 요청 을 프론트컨트롤러가 받는다.

 프론트 컨트롤러에는 URL과 각 컨트롤러에 대한 매칭 정보가 있는데, 이를 조회하여 컨트롤러를 호출한다.

 컨트롤러에서 jsp를 forward 한다.

 jsp파일로 http 응답을 한다.


스프링 MVC

내부 동작 정리 ( 알아두고 있으면 확장을 한다거나 문제 생겼을 때 원인 파악에 도움이 된다.)

 

 - DispatcherServlet

DispatcherServlet은 HttpServlet을 상속받아 사용하고 서블릿으로 동작한다.  스프링 부트가 DispatcherServlet을 서블릿으로 자동으로 동작하면서 모든 경로에 대해서 매핑한다.

 DispatcherServlet.java - doDispatch() 에서 URL에 매핑된 핸들러(컨트롤러를) 조회, 핸들러 어댑터 조회, 핸들러 어뎁터 실행, 핸들러 실행, ModelAndView 반환, viewResolver 호출, View 반환, View 랜더링 등의 일을 한다.

 

 - 주요 인터페이스 목록

핸들러 매핑: org.springframework.web.servlet.HandlerMapping

핸들러 어댑터: org.springframework.web.servlet.HandlerAdapter

뷰 리졸버: org.springframework.web.servlet.ViewResolver

뷰: org.springframework.web.servlet.View

 

 - HandlerMapping

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.java(isHandler메서드)가 스프링 빈 중에서 @RequestMapping 또는 @Controller가 클래스 레벨에 붙어 있는 빈을 매핑 정보로 인식한다. 애노테이션 설정된 빈을 못 찾으면 BeanNameUrlHandlerMapping.java가 스프링 빈의 이름으로 핸들러를 찾는다.

 

 - http요청에 따른 스프링 동작 흐름

1. DispatcherServlet이 브라우저로부터 요청을 받는다.

2. 요청 정보를 HandlerMapping 객체에 넘기고, 호출해야 할 Controller메서드 정보를 얻는다. ( 정확히는 HandlerAdapter 객체를 포함하는 HandlerExecutionChain 객체를 생성하여 넘기는 것)

3. DispatcherServlet이 HandlerExecutionChain객체에서 HandlerAdapter 객체를 가져와 메서드를 실행한다.

4. Controller 객체는 비지니스 로직을 처리하고 뷰에 전달할 데이터를 Model객체에 저장하여 DispatcherServlet에게 리턴한다.

5. DispatcherServlet은 View Name을 ViewResolver에게 전달하여 View객체를 얻어서 화면 표시를 요청한다.

6. view 객체가 해당 뷰를 호출하고 뷰는 화면을 표시한다. Model 객체에서 필요한 데이터를 가져와 화면에 같이 표시해준다.

 

 

컨트롤러 만들기

 

1. @Controller 혹은 @Component,@RequestMapping을 클래스 레벨에 붙인다.


2. @RequestMapping으로 url을 매핑한다. 

   1) @ReuqestMapping 조합

       url들에서 중복 되는 중복을 피하기 위해 중복 되는 부분은 @RequestMapping을 클래스 레벨에 설정, 나머지는 메세드 레벨에 붙여 조          합 해서 사용할 수 있다.

    2) http method 맵핑

      @GetMapping, @PostMapping, @DeleteMapping 안에 @ReuqestMapping이 들어있어서 http method도 맵핑을 간편하게 할 수 있다.

      ( @RequestMapping(value = "/save", method = RequestMethod.POST)  과 @PostMapping("/save")는 서로 같음)

 

3. ModelAndView에 모델,뷰 정보를 담아서 반환한다.
     1) application.properties에 뷰 이름 정보 설정 해둠
       spring.mvc.view.prefix=/WEB-INF/views/
       spring.mvc.view.suffix=.jsp )

     2) ModelAndView 대신  String으로 뷰의 논리 이름을 반환할 수 있다.

 

4. @RequestParam 사용

스프링은 HTTP 요청 파라미터를 @RequestParam 으로 받을 수 있다. @RequestParam("username") 은 request.getParameter("username") 와 거의 같은 코드라 생각하면 된다. 물론 GET 쿼리 파라미터, POST Form 방식을 모두 지원한다.

 

 

 


실습

[Spring Settings]

Project : Gradle - Groovy

Language : Java
Spring Boot : 2.7.6

Group : hello

Artifact : servlet

Name : servlet

Description : Demo project for Spring Boot

Pakage Name : hello.servlet

Packaging  : War  // jsp를 실습하기 위해 War 사용

Java : 11

Dependencies : Spring Web, Lombok     //spring web에 spring mvc가 들어있음

 GENERATE 수행

 

[intellij settings]

1. intellij에서 open :  GENERATE 수행해서 다운 받은 파일에서 build.gradle 파일

2. build.gradle 파일 확인

3. File - settings

 - Gradle 메뉴 : Build and run using과 Run tests using을 intellij IDEA   // gradle보다 intellij로 설정해야 run이 더 빠름

 - Plugins 메뉴 : Market Place 에서 Lombok 설치

 - Annotation Processors 메뉴 : Enable annotation processing 체크 // Lombok 실행시키기 위함

 

4. run

 


서블릿 등록 방법

 

1. ServletComponentScan 을 설정한다.

  • @ServletComponentScan 을 @SpringBootApplication 이 설정된 클래스에 추가

2. 서블릿을 등록한다.  3가지를 해줘야 함.

  • @WebServlet(name="", urlPatterns = "")
  • extends HttpServlet
  • service()함수

 

서버 로그에 http 정보 출력하는 방법

    # http 요청 정보를 로그에서 보기 위함  

   (운영 서버에는 모든 요청에 다 적용돼어서 성능 저하를 일으킬 수 있다. 개발 단계에서만 사용하자)

  • application.properties 파일에 설정 추가
# http 요청 정보를 로그에서 보기 위함  (운영 서버에는 모든 요청에 다 적용돼어서 성능 저하를 일으킬 수 있다. 개발 단계에서만 사용하자)
logging.level.org.apache.coyote.http11=debug

 

스프링 부트에서 / 요청 기본 설정은 index.html이다. ( 참고 https://wakestand.tistory.com/633)

 

 


 

JSP

jsp 추가시 build.gradle에 추가

//JSP 추가 시작
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'javax.servlet:jstl'
//JSP 추가 끝

 

jsp 파일 생성

 

jsp 문법

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%--jsp 파일이라는 뜻--%>

- webapp 밑에부터 절대경로를 만들면 된다. /jsp/members/new-form.jsp

- jsp에서는 servlet으로 자동으로 변환되기 때문에 몇가지 변수(request, response, out)를 바로 사용 가능하다.

  HttpServletRequest request

  HttpServletResponse response

  PrintWriter out = response.getWriter();

 

- jsp 파일에서  <% 자바코드 %> 를 사용해서 자바코드를 입력 가능하다.

- jsp 파일에서 <%@ page import="사용할 클래스" %> 로 자바에서 처럼 클래스 import가 가능하다.

- jsp 파일에서 <%= 자바코드 %> 를 사용해서 자바 코드를 출력할 수 있다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page import="java.util.List" %>
<%
    MemberRepository memberRepository = MemberRepository.getInstance();
    List<Member> members = memberRepository.findAll();
%>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/index.html">메인</a>
<table>
    <thead>
    <th>id</th>
    <th>username</th>
    <th>age</th>
    </thead>
    <tbody>
    <%
        for (Member member : members) {
            out.write(" <tr>");
            out.write(" <td>" + member.getId() + "</td>");
            out.write(" <td>" + member.getUsername() + "</td>");
            out.write(" <td>" + member.getAge() + "</td>");
            out.write(" </tr>");
        }
    %>
    </tbody>
</table>
</body>
</html>

 

jsp 파리미터 접근법을 이용하여 출력하면 간단하다.

java    request.setAttribute("member", member);

jsp      <%= ((Member)request.getAttribute("member")).getId() %>   // Member Import도 필요

           ${member.id}  // 파라미터 접근법

 

java(Controller)에서 ruqeust(Model)에 데이터를 담고  jsp(View)에서 request(Model)을 담긴 데이터를 꺼내 쓴다.

이 때 파라미터 접근법을 사용하면 간단하다. request.getAttribute()은 사용하기 번거롭고 import도 필요하다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="hello.servlet.domain.member.Member" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
성공
<ul>
  request.getAttribute을 사용하여 출력
    <li>id = <%= ((Member)request.getAttribute("member")).getId() %></li>
    <li>username = <%= ((Member)request.getAttribute("member")).getUsername() %></li>
    <li>age = <%= ((Member)request.getAttribute("member")).getAge() %></li>
    </br>
  프로퍼티 접근법을 사용하여 간단하게 출력 가능
    <li>id = ${member.id}</li>
    <li>username = ${member.username}</li>
    <li>age = ${member.age}</li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>

jstl 적용

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> // jstl을 사용하기 위한 선언

<c:forEach var="item" items="${members}">
    <tr>
        <td>${item.id}</td>
        <td>${item.username}</td>
        <td>${item.age}</td>
    </tr>
</c:forEach>