Spring Boot 3 & Spring Framework 6 - Section 7 :

이정수·2024년 7월 19일

Udemy학습-Spring & React

목록 보기
15/20
  • Web Application Concept :
    。Browser / HTML / CSS / Request / Response / Form / Session / Authentification

  • Spring MVC :
    。Dispatcher Servlet / View Resolvers / Model / View / Controller / Validation
    VIEW : html , JSP 처럼 client에게 보여주는 문서를 의미.

  • Spring Boot :
    。Starters / Auto Configuration .. etc

  • Framework :
    Framework : 재사용이 가능한 요소들의 집합으로서 정해진 구조, 틀 안에서 application을 용이하게 개발하는 용도.
    。JSP / JSTL / JPA / Bootstrap / Spring Security / MySQL / H2 DB

    해당 프로젝트에서 정의할 Spring Boot의 Starter와 Module dependency

    • Spring Web : spring-boot-starter-web
      。Web Application 개발에 필요한 실행환경 제공하는 Starter
      。Spring MVC를 이용하여 REST API를 포함한 Restful한 Web Application을 build시 사용.
      ▶ REST API를 구축하기 위해 필요한 dependency

      。기본 embedded container로 Apache Tomcat 활용.
      ▶ Dependency를 정의한 경우 Spring / Spring MVC / Tomcat / JSON Conversion의 기능을 사용 가능.

    • Spring Boot DevTools : spring-boot-devtools
      。코드 수정 시 수동으로 서버를 재시작하지 않아도 자동으로 재시작하여 Application을 변경하는 Spring Boot Module

JSP (Java Server Page) :
HTML를 기반으로 Java 코드를 삽입 및 활용하여 동적 웹페이지를 생성하는 Server-side script언어
JavaHTML에서의 Javascript와 유사한 역할로 활용할 수 있다.

JSP가 실행 시 Java servlet으로 변환 후 Web Application Server에 전달되어 기능을 수행하고 생성된 데이터는 Web Page와 함께 Client로 응답.

。 일반적으로 모든 JSP 파일은 Spring Boot에 의해 정의된 특정 폴더( src/main/resources ) 내부에서 제작.

<%-- sayHello.jsp --%>
<!doctype html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<p>hello</p>
</body>
</html>
<%-- html 구문을 그대로 복사 & 붙여넣기! --%>
  • JSP 태그 종류
    • 주석 : <%-- 내용 --%>
    • 선언 : <%! 내용 %>
      。선언 태그에서 선언 시 전역적으로 적용.
    • 지시자 : <%@ 내용 %>

      지시자 종류

      • <%@ page %>
        。해당 Page의 전체 속성 지정.

      • <%@ include %>
        。별도의 페이지를 현재 페이지에 삽입
        ex) JSPJSPF를 삽입

      • <%@ taglib %>
        taglib : 사용자가 만든 tag library를 사용하기위해 사용하는 JSP 지시자.
        ex) spring form taglib :
        <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

        uri="tag library 위치"
        prefix="tag를 지칭하는 이름"
    • 표현식 <%= 내용 %>
    • Scriptlet : <% 내용 %>
      。Scriptlet에서 선언 시 지역적으로 적용.
    • Java Bean 연결 : <jsp:action></jsp:action>
      。action


  • Java Servlet :
    。Java를 사용하여 웹페이지를 동적으로 생성하는 Server-side 프로그램
    ▶ Java 언어을 기반으로 Web Application 개발에 최적화한 library와 Class의 집합인 API로서 , 해당 API에 맞는 library 또는 class를 상속 및 구현하여 구성한 class를 Servlet이라고 한다.

    。Server-side에서 Web Client의 Request를 처리 후 Response.
    JSP가 HTML을 기준으로 Java 코드를 삽입하는 방식이면 Servlet은 온전히 Java코드를 활용해 생성.
  • JSP Framework의 dependency 정의
    。JSP를 tomcat에서 실행하려면 다음 dependency를 pom.xml에 정의 후 Maven 재실행.
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>
  • JSP 파일의 공통경로 지정.
src/main/resources/META-INF/resources/WEB-INF/jsp/sayHello.jsp
src/main/resources/META-INF/resources/WEB-INF/jsp/welcome.jsp
src/main/resources/META-INF/resources/WEB-INF/jsp/login.jsp
src/main/resources/META-INF/resources/WEB-INF/jsp/todos.jsp

。JSP파일을 생성 시 다음처럼 코드의 경로가 불필요하게 중복되는 경우가 많다.
▶ 공통경로부분을 application.properties접두어(prefix), 접미어(suffix)로 정의

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

。경로 src/main/resources/META-INF/resources/ 경로까지는 spring MVC에 의해 자동으로 식별.
▶ 그 이후의 공통적으로 겹치는 경로인 /WEB-INF/jsp/를 접두사로 설정.
▶ 이후 Controller Method를 통해 문자열 "sayhello"가 반환시 "/WEB-INF/jsp/sayhello.jsp" 경로의 JSP파일을 자동으로 참조.

JSP를 활용하는 간단한 Controller 구축

。 해당 @Controller가 선언된 Class는 @RequestMapping을 통해 URL이 부여된 Controller Method마다 해당 URL로 요청 시 문자열 , HTML , JSP를 반환.

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class sayHelloController {
    @RequestMapping("say-hello")
    @ResponseBody
    public String sayHello() {
        return "Hello World";
    }
    @RequestMapping("say-hello-html")
    @ResponseBody
    public String sayHelloHtml() {
        StringBuffer sb = new StringBuffer();
        sb.append("<!DOCTYPE html>");
        sb.append("<html lang=\"kor\">");
        sb.append("<head>");
        sb.append("<title>My first HTML Page</title>");
        sb.append("</head>");
        sb.append("<body>");
        sb.append("My first html page with body");
        sb.append("</body>");
        sb.append("</html>");
        return sb.toString();
    }
    @RequestMapping("say-hello-jsp")
    public String sayHelloJsp() {
        return "sayHello";
    }
}

@Controller : Spring Framework에서 Class가 Web Controller class를 정의.
▶ Client의 Request( URL )를 처리하고 Response를 보내는 역할을 수행.
@RequestMapping : Controller Method에 선언하여 Method와 Client의 요청 URL과 Mapping하는 역할을 수행.
@ResponseBody : 선언된 Controller Method가 반환하는 Data를 그대로 Request URL의 Client에게 반환하는 역할 수행.

sayHello() :
localhost:8080/say-hello 입력 시 @ResponseBody를 통해 문자열 "Hello World"을 그대로 브라우저에 전달하는 Controller Method.

sayHelloHtml() :
http://localhost:8080/say-hello-html입력 시 @ResponseBody를 통해 하드코딩 된 HTML Page 코드를 브라우저에 전달하는 Controller Method.
▶ 해당 HTML Page 코드는 StringBuffer에 입력된 후 한꺼번에 브라우저에 전달됨.

SayHelloJsp() :
localhost:8080/say-hello-jsp입력 시 /WEB-INF/jsp/sayhello.jsp를 redirection 하는 Controller Method.
application.properties에서 정의한 접두사 & 접미사와 jsp 파일명과 결합하여 View Resolver에 의해 JSP 파일을 참조 및 실행.

@ResponseBody를 선언하는 경우 "/WEB-INF/jsp/sayhello.jsp" 문자열을 브라우저에 그대로 전달하므로 사용하지않는다.

  • 이때, 진입한 웹페이지 화면에서 마우스 오른쪽버튼을 눌러 Inspect -> Network -> Doc -> say-hello-jsp로 진입 시 다음 화면이 나옴.
  • General :
    。Http Request URL과 Request Method를 지시.
    • @Controller :
      。Spring Framework에서 Class가 Web Controller class 일 경우 @Component 대신 선언.
      @Component구체화된 Annotation 중 하나로서 Spring bean 역할 수행.
      ▶ 주로 Web Application REST API의 Controller를 정의 시 사용.

      Servlet과 같이 Client의 Request를 처리하고 Response를 보내는 역할을 수행.
      @Controller가 선언된 class는 보통 HTTP Request를 처리하기위한 Controller Method들을 포함한다.
      ▶ 각 Controller Method@RequestMapping를 선언하여 사용하며 특정 URL의 요청을 처리하는 기능을 정의.

      Query Parameter활용 시 사용자의 Request를 처리한 후 View로 객체를 전달하는 중간 제어자 역할도 수행.

    • @RequestMapping(value = "url") :
      @Controller이 선언된 Web Controller ClassController Method를 정의 시 사용.
      。클라이언트의 요청(url)과 해당 Controller method를 mapping하는 annotation
      ▶ 해당 method는 요청을 처리하고 필요한 로직을 수행 후 응답 생성.

      。URL Mapping 방식을 세밀하게 제어 가능.

      @RequestMapping(value="url", method = RequestMethod.GET)
      。URL을 통해 localhost:8080/login으로 접속 시 해당 요청 URL의 Request Method에서 오직 GET에 대해서만 해당 Controller Method를 사용.
      method=RequestMethod.POST인 경우 해당 요청 URL의 POST에 대해서만 해당 Controller Method를 사용.



    • @GetMapping(path="url") REST API 활용
      @RequestMapping(path="url", method = RequestMethod.GET)와 비슷한 기능.
      ▶ 선언 할 경우 URL을 통해 접속 시 GET에 해당하는 Request에 대해서만 해당 Controller Method를 사용.

      REST API에 의한 Path Variable를 정의할 경우 path="URL"{Path Variable이름}을 추가해야한다.
      @GetMapping(path="/users/{id}")

      @PostMapping , @PutMapping 등의 어노테이션이 존재

    • @ResponseBody REST API 활용
      Controller Method의 return type을 JSON, XML format의 HTTP Response Body로 변환하여 Application에서 Client에게 반환.
      ▶ Server에서 Resource를 포함한 Response를 전송하기 위해 @ResponseBody를 Controller Method에 선언하여 HttpRequestBody의 객체(JSON)로 변환하여 Client에게 전송.
      • @Controller 선언된 Class의 경우
        Controller ClassController Method에 선언.
        ▶ 선언된 Controller Method가 반환하는 Data의 format을 그대로 @RequestMapping로 Mapping된 Request URL를 전송한 Client에게 반환하는 역할 수행.
        ▶ return하는 문자열 이름을 가지는 View Resolver를 통한 View의 조회를 무시하고 HTTPResponseBody에 문자열을 그대로 반환.

      • @RestController 선언된 Class의 경우
        。Class에 @RestController 선언 시 Controller Method 자동적용되므로 별도로 명시할 필요는 없다.


  • Http Status Code :
    • 1XX : Informational ( 정보제공 )
      。임시 응답
      。현재 클라이언트의 요청까지는 처리되었으므로 계속 진행을 지시

    • 2XX : Success ( 성공 )
      。클라이언트의 요청이 서버에서 성공적으로 처리
      • 200 : 전송 성공
      • 201 : Created : POST로 성공적으로 새로운 Resource가 생성됨.
      • 204 : No Content : Client의 Request를 처리했으나, Response할 데이터가 존재하지 않음.


    • 3XX : Redirection ( 리디렉션 )
      。완전한 처리를 위해 추가 동작이 필요한 경우
      。EX) 요청한 URL 웹문서가 이동했으므로 해당 주소로 다시 시도

    • 4XX : Client Error ( 클라이언트 에러 )
      。없는 페이지를 요청하는 경우
      • 400 : BadRequest : Client의 Request 구문이 문법상 오류 발생 또는 Validation Error이 발생한 경우
        ▶ EX) 요청 메시지 내용이 잘못된 경우
      • 403 : Client가 요청한 Resource에 대해 접근 권한이 없음을 지시
      • 404 : Resource를 발견하지 못한 경우


    • 5XX : Server Error ( 서버 에러 )
      。서버 사정으로 메시지 처리에 문제가 발생한 경우.
      。EX) 서버 부하 / DB 처리과정 오류 / Server에서 Exception이 발생한 경우.
      • 500 : Server Error : Server에서 오류발생 또는 Exception 발견.

Query Parameter 활용

。특정 URL을 통해 정보를 전달하는 방법 : ( @RequestParam , ModelMap )

  • URL을 localhost:8080/login?name=wjdtn747로 추가적인 요청 파라미터를 전달 시 처리하는 Cotroller Method 작성하기.
<!-- login.jsp -->
<!doctype html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    My Login Page with ${name}
</body>
</html>
     // gotoLoginPage
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class gotoLoginPage {
    @RequestMapping("login")
    public String gotoLoginPage(@RequestParam String name, ModelMap model) {
        model.put("name",name);
        return "login"; 
    }
}

localhost:8080/login?name=wjdtn747로 Query Parameter를 포함한 URL를 Request 할 경우
@RequestParam String name : URL의 Query Parameter인 name=wjdtn747의 값 wjdtn747를 String type으로 갖는 변수 name 설정.
ModelMap model : ModelMap의 객체 생성
ModelMap객체.put("JSP변수명",값) : VIEW에서 설정된 변수( ${name} )로 값을 전달.
application.properties의 접두사, 접미사를 통해 /WEB-INF/jsp/login.jsp로 결합 및 redirection되어 View Resolver에 의해 JSP파일이 참조 및 실행.

  • @RequestParam :
    。URL의 Query ParameterController Method의 매개변수로 Binding.
    。ex) /login?name=wjdtn747일 경우,
    매개변수에 @RequestParam String name 설정 시 URL의 Query Parametername 값 wjdtn747이 전달됨.
    @RequestParamGET의 Query Parameter 뿐만 아니라, POST method를 통해 전달되는 Form Data도 전달 받을 수 있다.

  • ModelMap :
    Model interface를 구현한 구현체.
    。Controller Method의 매개변수에 ModelMap modelmap객체를 추가한 후 modelmap객체.put()을 통해 data를 추가하여 VIEW( jsp )로 전달.
    ▶ JSP에 전달할 Data를 ModelMap에 전부 추가한 후 한꺼번에 JSP에 전달.
    • Model :
      。스프링이 지원하는 기능으로서 key, value로 구성된 HashMap.
      ModelMap으로 Model interface를 구현.
      View에 전달할 데이터를 저장 가능하며 View에서는 expression language( ${변수명} )로 해당 데이터를 활용.

    • ModelMap객체.put("JSP변수명",값)
      ControllerMethod 내부에서 JSP에서 정의된 JSP변수명과 전달값을 입력.
      JSP 에서는 Expression Language(ex. ${변수이름} )를 이용해 변수에 데이터를 전달.

    • ModelMap객체.get("VIEW의 변수이름")
      Model을 통해 VIEW에서 정의된 해당 JSP변수의 값을 Java로 가져오는 역할을 수행.

    • ModelMap객체.addAttribute("JSP변수명",변수값) :
      JSPExpression Language로 작성된 변수( ${변수명} )에 Data를 전달하는 역할을 수행.
      ModelMap객체.put("변수명",변수값)과 동일한 기능으로 작용하지만 @SessionAttributes("JSP변수명")으로 Model에 저장되는 data를 HttpSession에 전달 시 ModelMap객체.addAttribute를 사용.
  • Web Application 구동 순서. MVC 설명
    • #1. Dispatcher Servlet에서 Client로 부터의 HttpRequest를 수신.

    • #2. Dispatcher Servlet에서 HttpRequest의 URL을 통해 해당 요청을 처리할 수 있는 적절한 ControllerController Method를 식별.
      ex) localhost:8080/login 일 경우, @Controller가 선언된 Controller class의 @RequestMapping("Login")이 선언된 Controller Method를 식별.

    • #3. 해당 Controller methodModel을 생성 및 View의 이름을 return.
      Controller Method의 매개변수에 ModelMap model을 생성하여 model.put("name",name);을 통해 ModelMap에 name라는 변수를 생성하여 전달값을 넣고, "Login" 문자열의 View 이름을 return.

    • #4.return된 View 이름을 통해 Rendering할 적절한 View를 ViewResolver로 식별하여 해당 View의 코드를 실행.
      application.properties에서 prefix, suffix를 설정하고, Controller Method에서 return된 "Login"을 이용하여 결합된 /WEB-INF/jsp/Login.jspView Resolver를 통해 Login.jsp를 찾아서 실행.

    • #5. 이후 HttpResponse를 브라우저로 return.

로그인 양식 만들기

  • 사용자가 ID, PW를 입력 시 해당 사용자의 ID와 PW를 검증 후 간단한 환영 페이지 출력해보기.
  • 이때 검증하는 단계는 Spring Security Framework를 이용해야하여 검증해야하나, 현 단계에서는 안함.
  • JSP를 통해 로그인 페이지 작성하기

    활용할 html 구문 HTML 코드

    • <form> :
      。사용자 의견, 정보를 알기 위해 입력할 큰 틀을 생성하는데 사용.
      。페이지 내에서 입력양식 전체를 의미하는 추상적 개념의 태그.
      。입력된 데이터를 한번에 서버로 전송하여 웹서버가 처리 후 결과에 따른 또 다른 웹페이지를 보여줌.
      • method="" :
        Http Resquest MethodGET, POST.. 로 임의 설정.
        。기본값은 GET

        <form method="get">로 내부의 <input>된 정보를 submit 할 경우 URL의 Queryparameter로서 전달됨.
        <form method="post">로 내부의 <input>된 정보를 submit 할 경우 <form>의 data로서 전달됨.
        ▶ Form Data의 경우 ChromeInspection - Network - Doc - Payload를 통해 확인!
        POST가 보안측면에서 더 안전하다.
    • <input type="text"> :
      <form>의 자식요소로서 사용자로부터 입력을 받을 수 있는 input field를 정의


  • Java의 Controller Class와 JSP의 HTML 코드 설정
    // gotoLoginPage.java
@Controller
public class gotoLoginPage {
    @RequestMapping("login")
    public String gotoLoginPage() {
        return "login";
    }
}

localhost:8080/login 입력 시 application.properties에 정의된 prefix , suffixController Method에서 return된 "login"을 통해 /WEB-INF/jsp/login.jspViewResolver를 통해 검색하여 실행.

     <!-- login.jsp -->
<html lang="kor">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form>
        <h2>My Login Page</h2>
        <label for="textid">Id</label>
        <input type="text" id="textid" name="idName">
        <label for="textpw">Password</label>
        <input type="password" id="textpw" name="idPassword">
        <button type="submit">submit</button>
    </form>
</body>
</html>


。각 html element를 하나의 <form>에 넣은 후 각각의 <input> field에 값을 입력 후 <button>을 누를 경우 Client에서 Server에 Request 되는 Request URL의 일부로서 query parameter에 포함.
<input>name=""는 query parameter의 변수명으로 설정되어 ?변수명=입력값꼴로 전달됨을 확인 가능.

。Application에 액세스할 때마다 인터넷의 수많은 라우터를 통하여 사용자 정보를 URL의 QueryParameter로서 전송하는건 보안상 안전하지않다.
。Http Request Method를 GET으로 설정하여 사용자 정보 전송 시 URL의 Query Parameter로서 전송됨.
<form method="post">를 설정하여 Http Request Method를 POST로 설정하여 사용자의 정보가 <form> data로서 전달되도록 설정.

<form method="post"> 으로 수정하여 ID와 PW를 입력할 경우 사용자의 정보가 URL의 Query parameter가 아닌 Form Data의 일부로서 전달됨.
▶ Form Data의 경우 ChromeInspection - Network - Doc - Payload를 통해 확인!

  • 웹사이트로 전송하는 모든 사용자정보는 항상 POST를 사용해 Form Data의 일부로서 전송하는것이 좋다!

로그인 페이지에서 리디렉션할 환영 페이지 생성하기.

  • 환영페이지 : welcome.jsp로 작성.
    <html lang="kor">
      <head>
          <title>Welcome Page</title>
      </head>
      <body>
          <div>Welcome to wjdtn747</div>
          <div>Your name : ${name}</div>
          <div>Your Password : ${name}</div>
      </body>
    </html>
    。브라우저에 localhost:8080/login을 통해 login 페이지 접속 시, 초기 전달될 Request MethodGET.
    。ID와 PW를 입력하여 제출버튼을 누를 경우, 전달될 Request MethodPOST
    ▶ RequestMethod : POST인 경우의 다른 JSP Page 표현하기.

  • 동일 URL의 다른 Request Method에 대해서 따로 처리하는 Controller Method 제작
    @RequestMapping(value="URL", method = RequestMethod.GET)
    。URL을 통해 localhost:8080/login으로 접속 시 해당 요청 URL의 Request Method에서 오직 GET에 대해서만 해당 Controller Method를 사용.
                // gotoLoginPage.java
    package com.wjdtn747.springframework.todo1.Controller;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    @Controller
    public class gotoLoginPage {
      @RequestMapping(value = "login", method= RequestMethod.GET)
      public String gotoLoginPage(){
          return "login";
      }
    }
    @RequestMapping(value = "login", method= RequestMethod.GET)
    。초기 URL 접속 시 GET에 대해서 정의된 Controller Method만 존재하므로 반환되는 "login"을 통한 ViewResolver 기능으로 login.jsp가 표시.
    。ID와 PW를 입력 후 POST로 전송 시 동일 URL에 대해 POST가 정의된 Controller Method가 존재하지 않으므로 Error Page가 도출.
         // gotoLoginPage.java
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    @Controller
    public class gotoLoginPage {
      @RequestMapping(value="login", method= RequestMethod.GET)
      public String gotoLoginPage() {
          return "login";
      }
      @RequestMapping(value="login", method=RequestMethod.POST)
      public String gotoLoginPagewPOST(@RequestParam String idName, @RequestParam String idPassword, ModelMap model) {
          model.put("name",idName);
          model.put("password",idPassword);
          return "welcome";
      }
    }
    。동일 URL에 POST를 정의 및 "welcome"을 반환하여 ViewResolver 기능으로 welcome.jsp를 표시하는 Controller Method 생성.
    POST를 통해 form data로 전달된 ID와 PW를 @RequestParam을 통해 Controller Method의 매개변수로 받아온다.
    @RequestParamGET의 Query Parameter 뿐만 아니라, POST method를 통해 전달되는 Form Data도 전달 받을 수 있다.
    ▶ 해당 매개변수의 이름은 HTML tag의 <input name="">name 속성 이름과 동일해야한다.

    ex) /login?name=wjdtn747일 경우,
    매개변수에 @RequestParam String name 설정 시 name 값이 wjdtn747로 설정됨.

    ModelMap을 통해 전달된 ID와 PW를 JSP에 전달하여 표현.
    ModelMap객체.put("JSP변수명",전달값)

    。초기 localhost:8080/loginGET으로 접속 시 login.jsp가 도출되어 ID와 PW를 입력하여 POST로 submit 할 경우 welcome.jsp가 도출되어 form data로 전달된 ID와 PW가 페이지에서 도출.
  • ( 하드코딩 ) 사용자 ID와 PW 검증 추가하기
    하드코딩으로 특정 ID, PW 입력 시 사용자를 환영페이지로 리디렉션하고 틀릴경우 로그인페이지로 돌려보내기
    。비추천.
    • 인증을 담당하는 클래스 생성하기.
      。class는 Spring이 Autowiring 하도록 Spring Bean으로 제작해야함.
      => 해당 class는 business logic을 수행하므로 @Service를 선언.
     import org.springframework.stereotype.Service;
    // Spring Bean으로 제작하기.
    // 해당 클래스는 Business logic을 수행!
    @Service
    public class AuthenticationService {
        public boolean authenticate(String username, String password){
            boolean isValidUsername = username.equalsIgnoreCase("wjdtn");
            boolean isValidPassword = password.equalsIgnoreCase("123456");
            // AND 연산자로서 둘다 TRUE여야 TRUE를 반환.
            return isValidUsername && isValidPassword;
        }
    }
    • 이때, 해당 AuthenticationService class의 참조변수를 생성 후 초기화 시, Spring에서 new AuthenticationService()로 직접 instance를 생성해서 결합하면 좋지않음.
      => Spring에서 초기화 시 가장 이상적인 방법은 생성자주입을 이용하는 방법.
    • 에러메시지를 출력 시 model을 생성해서 오류 메시지를 넣어주기.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class LoginController {
    // 입력된 ID, PW를 비교하는 Class 객체참조변수 생성.
    private AuthenticationService authenticationService;
    // 생성된 객체참조변수에 @Autowired를 이용한 생성자주입을 통해
    // Spring Bean으로 선언된 AuthenticationService를 찾아 주입.
    @Autowired
    public LoginController(AuthenticationService authenticationService) {
        super();
        this.authenticationService = authenticationService;
    }
    @RequestMapping(value = "login", method= RequestMethod.GET)
    public String gotoLoginPage(){
        return "login";
    }
    @RequestMapping(value = "login", method = RequestMethod.POST)
    public String gotoWelcomePage(@RequestParam String name, @RequestParam String password, ModelMap map){
        // ID와 PW의 입력된 문자열을 각각 비교한 후
        // 모두 TRUE일 경우 TRUE를 반환하는 메소드.
        // if 조건이 true인 경우, welcome.jsp를 실행하게하고
        // false인 경우 login.jsp를 실행.
        if(authenticationService.authenticate(name, password)){
            map.put("name",name);
            map.put("password",password);
            return "welcome";
        }else{
            // 에러메시지를 모델로 jsp에 전달.
            map.put("errMessage","ID or PW uncorrected.");
            return "login";
        }
    }
}
<html lang="kor">
  <head>
      <title>My first Login Page</title>
  </head>
  <body>
      My Login page with body
      <pre>${errMessage}</pre>
      <form method="post">
          Name : <input type="text" name="name">
          Password : <input type="password" name = "password">
          <input type="submit">
      </form>
  </body>
</html>
  • ID와 PW를 잘못 입력하면 다음처럼 도출.
    • <pre> :
      。미리 정의된 서식의 텍스트를 정의할 때 사용.
      <pre> 태그 내에서는 텍스트 작성 시 space, tab, enter 등이 반영된다.

    • A문자열.equalsIgnoreCase(B문자열) :
      。대소문자 차이를 무시하면서 두 문자열을 비교하는 역할 수행.

TO-DO 관리 Application 구축하기.

。웹페이지에 적절한 구조를 설치하기.
。설명 / 목표날짜 / 완료 여부 저장, 업데이트, 삭제 기능 구현

  • TO-DO 정보를 저장할 Spring Bean 생성
    Todo Class 객체는 DB에 Data를 전달하는 instance로서 id / username / description / targetDate / completed의 Field를 포함.
    ▶ 생성자주입 및 Getter & Setter 정의하기.
import java.time.LocalDate;
public class Todo {
    private int id;
    private String username;
    private String description;
    private LocalDate targetDate;
    private boolean completed;
    public Todo(int id, String username, String description, LocalDate targetDate, boolean completed) {
        this.id = id;
        this.username = username;
        this.description = description;
        this.targetDate = targetDate;
        this.completed = completed;
    }
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    public LocalDate getTargetDate() { return targetDate; }
    public void setTargetDate(LocalDate targetDate) {  this.targetDate = targetDate; }
    public boolean isCompleted() { return completed; }
    public void setCompleted(boolean completed) { this.completed = completed; }
}
  • To-DO 정보를 DB에 전달할 List 생성
    staticList 자료형을 생성 후 실제 DB로 전달
    ▶ 이때, Static List로 데이터 저장 시 서버가 재시작 될때마다 초기화되므로 MySQL 등과 같은 DB를 활용.

    static 변수를 초기화 설정 시에는 static block을 생성해야한다.

    static block : Java Class 내부의 명령문 Block으로서 생성자가 instance를 초기화하는것처럼 static 형식의 Data(변수/상수)를 초기화.
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@Service
public class TodoService {
    // static List 자료형 생성
    private static List<Todo> todos=new ArrayList<>();
    // List 자료형 초기화
    // 이때, static 변수는 static block으로 초기화.
    static{
        todos.add(new Todo(1,"wjdtn747","Learn AWS", LocalDate.now().plusYears(1),false));
        todos.add(new Todo(2,"wjdtn0619","Learn DevOps", LocalDate.now().plusYears(2),true));
        todos.add(new Todo(3,"wjdtn3902","Learn FullStackDevelopment", LocalDate.now().plusYears(3),false));
    }
    public List<Todo> findByUsername(String s){
        return todos;
    }
}

@Service는 해당 Class가 Spring Bean임과 동시에 business logic에 구체화되었으므로 @Component 대신 선언.
。static의 ArrayList 변수를 생성 후 static block을 통해 해당 변수를 초기화 설정.

  • Model 구현체( ModelMap )에 추가되는 변수(name)를 HttpSession에 저장
    ModelMap을 통해 JSP( welcome.jsp )에 전달된 data를 다른 JSP 페이지( listTodos.jsp )로 렌더링하여 연결이 끊기더라도 HttpSession에 저장하여 listTodos.jsp에서 사용할 수 있게하기.
    welcome.jsp에 전달하고자 생성된 ModelMap model객체에 model.put("name",idName)@SessionAttributes("name")를 통해 Session에 전달.

    <a href="url"> :
    <a>는 하나의 페이지에서 다른 페이지로 연결시 사용하는 하이퍼링크를 정의 시 사용.
    href="URL" 속성은 링크된 페이지의 목적지 URL을 명시하는 역할을 수행.
<!-- welcome.jsp -->
<html lang="kor">
    <head>
        <title>Welcome Page</title>
    </head>
    <body>
        <div>Welcome to wjdtn747</div>
        <div>Your name : ${name}</div>
        <div><a href="list-todo">Manage</a> your todos</div>
    </body>
</html>
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
@SessionAttributes("name")
public class gotoLoginPage {
    @RequestMapping(value="login", method= RequestMethod.GET)
    public String gotoLoginPage() {
        return "login";
    }
    @RequestMapping(value="login", method=RequestMethod.POST)
    public String gotoLoginPagewPOST(@RequestParam String idName, @RequestParam String idPassword, ModelMap model) {
        model.addAttribute("name",idName);
        model.addAttribute("password",idPassword);
        return "welcome";
    }
}

ModelMap에 추가된 Data( model.addAttribute("name",idName) ) 중 Session에 전달할 Data의 JSP변수명( name )을 @SessionAttribute("name")로 선언하여 Session에 전달.

ModelMap객체.addAttribute("JSP변수명",변수값) : ModelMap객체.put("JSP변수명",변수값)과 동일한 기능으로 작용하지만 @SessionAttributes("JSP변수명")으로 Model에 저장되는 data를 HttpSession에 전달 시 ModelMap객체.addAttribute를 사용.

  • URL과 To-Do Page를 Mapping할 Controller Class 생성
    JSP를 이용한 리디렉션 기능 구현.
    ▶ 해당 listTodos.jspgotoLoginPage Class의 Model로부터 Session에 전달된 name@SessionAttributes("name")를 통해 TodoController Class에 전달받아서 변수 ${name}로 이용.
// TodoController
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import java.util.List;
@Controller
@SessionAttributes("name")
public class TodoController {
    private TodoService todoService;
    // 생성자기반 Dependency Injection.
    // @Autowired 없음.
    public TodoController(TodoService todoService) {
        this.todoService = todoService;
    }
    @RequestMapping("list-todo")
    public String ListAllTodos(ModelMap model){
        List<Todo> todos = todoService.findByUsername("wjdtn747");
        model.put("todos",todos);
        return "listTodos";
    }
}
}

@SessionAttributes("name") : gotoLoginPageModel data를 @SessionAttributes("name")를 통해 전달받아서 listTodos.jsp에 전달.

<!-- listTodos.jsp -->
<html lang="kor">
    <head>
        <title>List Todos Page</title>
    </head>
    <body>
        <div>Welcome to ${name}</div>
        <div>Your Todos are ${todos}</div>
    </body>
</html>

@SessionAttributes("name") :
TodoController Class에서 선언할 경우 gotoLoginPage Class의 Model에 추가된 변수(name)를 해당 gotoLoginPage Class에서 선언된 @SessionAttributes("name")을 통해 listTodos.jsp의 (${name}) 변수로 전달됨.

로그인 페이지를 통해 list-todo로 접속 시 todo data를 표현.

。login page에서 list-todo Page로 렌더링 했는데도 불구하고 gotoLoginPage에서 Model을 통해 Session에 전달한 변수 "name"를 여전히 사용 가능하다.
▶ 변수 "name"이 Session Scope에 저장되었으므로 사용이 가능.

  • @SessionAttribute("Model에 추가된 변수명")
    。특정 JSP에 전달하고자 설정한 Model 객체(ModelMap)에 저장되는 데이터를 HttpSession에 저장하여 다른 JSP페이지로 렌더링되어 연결이 끊기더라도 Model 객체의 Data가 유지되도록 해주는 Annotation
    @Controller를 선언한 Web Controller class앞에 선언해서 View에서 사용하고자 Model에 추가한 변수명을 Session에 input.
    ▶ Annotation에 선언된 Model의 data를 사용 시, 항상 해당 Model 객체의 Data를 사용하는 JSP가 Mapping된 모든 Controller class 앞에 선언해야한다.

HTTP (Hyper Text Transfer Protocol) :
。Web Server와 Web browser 간 데이터를 교환을 위해 사용되는 Protocol.
Protocol : 컴퓨터 내부, 컴퓨터 간 교환되는 데이터 형식의 규칙의 집합.

。Http 프로토콜은 기본적으로 상태를 유지하지 않는 Stateless 특징을 지니는 프로토콜이므로, 다른 JSP로 이동하여 연결을 끊을 경우 해당 JSP상의 데이터가 다 사라지므로 Web Server는 다른 JSP 페이지로 이동 시 데이터를 보존하기위해 session 등을 사용.
HTTP Protocol 특징

  • Request :
    。요청에 존재하는 모든 값은 각각의 요청에 대해서만 유효
    。다음 페이지를 렌더링하기 위해서만 사용되며 다음페이지로 렌더링 이후로는 사용이 불가능.

  • Model :
    。스프링이 지원하는 기능으로서 key, value로 구성된 HashMap.
    ModelMap으로 Model interface를 구현.
    View에 전달할 데이터를 저장 가능하며 View에서는 expression language( ${변수명} )로 해당 데이터를 활용.
    。Request와 동일하게 다른 페이지로 렌더링 시 사용이 불가능.

    • Map :
      keyvalue로 구성된 Entry 객체를 저장하는 구조를 지닌 자료구조.
      entry : key-value 쌍

    • HashMap :
      。Map Interface를 구현한 대표적인 Map Collection.
      ▶ Map Interface를 상속하므로 Map의 성질을 그대로 지님.


  • Session :
    。Browser와 Server 간의 송수신 연결상태를 의미
    。Web Application에서 사용자의 상태정보를 유지하기위한 메커니즘.

    Server-side에서 관리하는 정보.
    Http Session id를 식별자로 구별하여 접속한 Server의 DB에 정보를 저장.
    • Model :
      。Model에 넣는 모든 값은 Request Scope가 Default.
      @SessionAttribute를 통해 Session Scope를 지정 가능.
      • Request Scope :
        。오직 하나의 request에만 적용.
        。response가 전송될 경우, request attribute가 메모리에서 삭제.
        。대부분의 사례에서 활용.

      • Session Scope :
        。세부정보가 다수의 request에 걸쳐서 저장.
        。해당 범위를 사용 시 추가적으로 메모리를 차지하고, 모든 세부정보가 서버에서 저장되므로 사용에 주의를 둬야한다.

JSTL(JSP Standard Tag Library) :
。JSP Page에서 자바코드 없이 <html> 태그형식으로 간편하게 데이터를 출력할 수 있도록 나온 라이브러리.
▶ JSP Page에서 연산, 조건문, 반복문, DB 등을 처리하게 할 수 있음.

pom.xml에 다음 dependency를 추가.
JSTL API Dependency
JSTL Implementation Dependency

<dependency>
            <groupId>jakarta.servlet.jsp.jstl</groupId>
            <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
</dependency>
<dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>jakarta.servlet.jsp.jstl</artifactId>
</dependency>
  • JSTL 태그 종류
    JSTL 활용 시 JSP 상단에 다음 태그를 작성한 후 연산 사용.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
  • Core (prefix="c")
    。일반 프로그래밍에서 제공하는 것과 유사한 변수 선언
    。실행흐름제어 & 페이지 이동기술 제공
    。URI :
    http://java.sun.com/jsp/jstl/core
    • forEach 함수 : foreach 역할 수행.
    <c:forEach items="${todos}" var="todo">

    items : Java에서 Model을 통해 전달된 source로서 List 형식 변수를 지정.
    var : <c:forEach> 구문 내에서 사용할 변수 이름을 지정.



  • Formatting (prefix="fmt")
    。숫자, 날짜, 시간을 formatting.
    。URI : http://java.sun.com/jsp/jstl/fmt

  • DB (prefix="sql")
    。DB data 입력, 수정, 삭제, 조회 기능 제공
    。URI : http://java.sun.com/jsp/jstl/sql

  • XML (prefix="xml")
    。XML문서 처리 기능 제공.
    。URI : http://java.sun.com/jsp/jstl/xml

  • Function (prefix="fn")
    。문자열 함수 제공.
    。URI : http://java.sun.com/jsp/jstl/functions
  • HTML 태그 활용
    。html에서 표를 구현 시 기본적으로 table 태그 안에 tr, td, th를 넣어 행, 열, 제목을 지정하여 표를 구축.
    • <table>
      <tr> table row : 행
      <td> table data : 행의내용
      <th> table heading : 행, 열의 제목
      <thead> : 머리글
      <tbody> : 본문
      <tfoot> : 꼬리말
    • <div> division :
      。HTML 문서 내 한줄의 가로(Block) 공간을 생성.
    • <h1> heading : 해당 영역의 제목 지시
    • <hr> a horizontal rule :
      。웹페이지에 가로로 선을 긋는 태그
      。다른 컨텐츠를 구분하는 역할.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html lang="kor">
    <head>
        <title>List Todos Page</title>
    </head>
    <body>
        <div>Welcome ${name}</div>
        <hr>
        <h1>Your Todos</h1>
        <table>
            <thead>
                <tr>
                    <th>id</th>
                    <th>Description</th>
                    <th>Target Date</th>
                    <th>Is Done?</th>
                </tr>
            </thead>
            <tbody>
                <!-- taglib 선언 후 다음 forEach 함수 사용 가능. -->
                <c:forEach items="${todos}" var="todo">
                    <tr>
                        <td>${todo.id}</td>
                        <td>${todo.description}</td>
                        <td>${todo.targetDate}</td>
                        <td>${todo.completed}</td>
                    </tr>
                </c:forEach>
            </tbody>
        </table>
    </body>
</html>


▶ 다음처럼 결과 도출.

Bootstrap :
Front-end 개발을 용이하기위해 트위터에서 사용하는 각종 레이아웃, 버튼, 입력창 등의 디자인을 CSSJavascript로 구축한 CSS Framework.
HTML & CSS Template의 양식, 버튼 등 다양한 웹페이지 구성요소를 포함.

Bootstrap 사용 준비

  • 기존 방법 : Bootstrap 웹페이지에서 수동으로 Bootstrap CSS 파일을 다운로드 후 스프링 프로젝트의 static폴더에 넣어서 사용

  • webjars : org.webjars
    。Client-side ( UI )에서 사용되는 웹라이브러리( jquery, bootstrap, react.js, vue.js, Angular )등을 JAR 파일 안에 패키징.
    。Spring boot는 Webjars에 대한 mapping을 제공하므로, pom.xml에 dependency로서 정의 가능.

    JAR( .jar : Java ARchive) :
    。여러 개의 Java Class 파일, 메타 데이터, Resource 파일 등을 하나의 파일로 묶은 Archive 파일.
    。필요한 기본적인 dependency들을 전부 구성하여 간편하게 사용가능하게하는 Starter Project 역할 수행.



  • JQuery :
    。JavaScript의 Library
    。기존의 javascript를 통한 작성방식에 비해 간단하게 작성하여 동일 결과를 도출 가능.
<dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>5.1.3</version>
</dependency>
<dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.6.0</version>
</dependency>

webjarsjquerybootstrap을 포함.
pom.xml에 다음 2개의 dependency를 입력하여 webjars를 사용.

  • pom.xmlwebjars의 dependency를 정의한 후 bootstrap.min.css / bootstrap.min.js 파일의 경로를 찾기
    External Libraries - Maven: org.webjars:bootstrap:5.1.3

    \META-INF\resources\webjars\bootstrap\5.1.3\css\bootstrap.min.css
    \META-INF\resources\webjars\bootstrap\5.1.3\js\bootstrap.min.js

    External Libraries - Maven: org.webjars:jquery:3.6.0에서 jquery.min.js를 동일하게 찾은 후 copy path.

    \META-INF\resources\webjars\jquery\3.6.0\jquery.min.js
    ▶ 이후 적용할 jsp파일에 해당 경로들을 활용.
webjars/bootstrap/5.1.3/css/bootstrap.min.css
webjars/bootstrap/5.1.3/js/bootstrap.min.js
webjars/jquery/3.6.0/jquery.min.js

webjars를 이용해 js , css 사용 시 /META-INF/resources/ 를 지정할 필요가 없음.

Bootstrap으로 페이지를 formatting하기.

  • Bootstrap frameworkjQuery Library를 JSP에 불러오기.
    。웹페이지 로딩 시 CSS 파일이 먼저 로딩됨.
    html에서 css 활용 시 <head>부분에 <link>를 정의하여 파일을 연결.
<link href="webjars/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">

html에서 javascript 활용 시 body의 종료태그 </body> 앞에 <script>를 통해 파일 연결.

<script src="webjars/bootstrap/5.1.3/js/bootstrap.min.js"></script>
 <script src="webjars/jquery/3.6.0/jquery.min.js"></script>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html lang="kor">
    <head>
        <!-- css 파일 설정 -->
        <link href="webjars/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
        <title>List Todos Page</title>
    </head>
    <body>
        <!-- div class 지정. -->
        <div class="container">
            <h1>Your Todos</h1>
            <table class="table">
                <thead>
                    <tr>
                        <th>id</th>
                        <th>Description</th>
                        <th>Target Date</th>
                        <th>Is Done?</th>
                    </tr>
                </thead>
                <tbody>
                    <!-- taglib 선언 후 다음 forEach 함수 사용 가능. -->
                    <c:forEach items="${todos}" var="todo">
                        <tr>
                            <td>${todo.id}</td>
                            <td>${todo.description}</td>
                            <td>${todo.targetDate}</td>
                            <td>${todo.completed}</td>
                        </tr>
                    </c:forEach>
                </tbody>
            </table>
        </div>
        <!-- script 파일 설정 -->
        <script src="webjars/bootstrap/5.1.3/js/bootstrap.min.js"></script>
        <script src="webjars/jquery/3.6.0/jquery.min.js"></script>
    </body>
</html>

。이후 <body> 내부 내용을 <div class="container">에 넣고 <table class="table">로 수정하여 JSP파일 정의.

  • bootstrap에 의해 HTML의 format이 약간 변형한걸 확인 가능.

    。브라우저에서 URL을 입력하여 Request 시 브라우저로 전송되는 Response로서 list-todo가 전달됨.
    ▶ 브라우저는 list-todo의 contents에 bootstrap의 css,js파일의 link를 관측 후 해당 파일들을 전부 다운로드.

    Bootstrap은 <div><table>에 대해 많은 class를 제공.

    • <div> :
      。기존 class=""는 좌측정렬이지만, <div class="container"> 설정 시 중앙정렬.
    • <div> :
      <table class="table"> 설정 시 다음 디자인이 제공.
profile
공부기록 블로그

0개의 댓글