ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 학원 day88. @RequestParam, URL 매핑, SessionUtils
    기록 2023. 1. 6. 21:18

    스프링을 사용하는 이유.

    1. 스프링이 제공하는 의존성 주입을 사용하기 위해서 도입한다.

    2. 웹 어플리케이션 프로그램을 쉽게 개발할 수 있다. 

    3. 다양한 db엑세스 기술과 연동해서 개발할 수 있다.

     

    객체마다 의존성을 갖고 있다. 

    클라이언트의 요청이 실행되기 위해서는 업무로직이 필요하고,

    업무로직이 실행되기 위해서는 DB엑세스가 필요하다. 

     

    컨트롤러 객체 - 사용자의 요청을 처리, 사용자에게 데이터 제공

    서비스 객체 - 업무로직 수행

    매퍼객체(DAO) - 데이터베이스 엑세스 수행

     

    스프링에게 객체의 생성을 위임했다.

     

    web-context.xml

    <context:component-scan base-package="com.sample.web" /> 코드를 통해서

    com.sample.web 패키지 및 그 하위 패키지에서 

    @Controller, @ControllerAdivice, @RestController, @RestControllerAdvice, @Repository, @Service, @Configuration, @Component 등의 어노테이션이 부착된 클래스를 전부 스캔해서 객체를 생성한다. 

     

    service-context.xml

    <context:component-scan base-package="com.sample.service" /> 코드를 통해서

    com.sample.service 패키지 및 그 하위 패키지에서 

    @Controller, @ControllerAdivice, @RestController, @RestControllerAdvice, @Repository, @Service, @Configuration, @Component 등의 어노테이션이 부착된 클래스를 전부 스캔해서 객체를 생성한다. 

     

    스프링 컨테이너 이름은 XmlWebApplicationContext이다.

     

    스프링이 갖고있는 어노테이션 프로세서들이 어노테이션들을 분석해서 적절한 작업을 수행한다. 객체들을 조립한다.

     

    SqlSessionFactory는 mybatis의 핵심객체이다. SqlSession을 제공한다.

    SqlSession이 있어야 update,delete, insert를 할 수 있다.

     

    database-context.xml

    <bean id="dateSource" class="DriverManagerDataSource">,

    <bean id="sqlSessionFactory" class="SqlSessionFactoryBean">

    <mybatis-spring:scan base-package="com.sample.mapper"/>

    코드를 통해서

    com.sample.mapper 패키지의 모든 매퍼 인터페이스를 스캔해서 인터페이스를 구현한 매퍼 인스턴스(인터페이스 구현객체)를 생성하고 스프링의 빈으로 등록시킨다.

     

    스프링 컨테이너에 등록해야지 다른 곳에 주입할 수 있다.

     

    DriverManagerDataSource, SqlSessionFactory, MapperScannerConfigurer는 우리가 설정파일에 코드를 적어서 객체를 만들지만, 컨트롤러 객체, 서비스 객체, 매퍼 객체는 스프링이 스캔해서 자동으로 등록시켜준다.

    의존성 정보를 분석해서 적절한 객체를 조립해주기까지 한다. (@Autowired 어노테이션을 붙여서 의존성 정보를 표현)

     

    의존성주입 : 

    자신의 컨테이너에 없으면 부모 컨테이너에 가서 찾는다.

    부모 컨테이너에 있으면 변수명에 객체의 주소를 대입한다.

     

    중요한건 의존성을 정의하는 것!!

    값을 전달하는 방법 - 요청핸들러 메소드의 매개변수가 기본자료형 혹은 String형 인 경우
    * 매개변수의 이름과 동일한 이름으로 요청파라미터 값을 조회해서 매개변수로 전달한다. (매개변수이름은 .jsp에서 name으로 정해준 이름을 쓴다.)
     *  매개변수의 타입이 기본자료형 타입인 경우 해당 타입으로 형변환해서 전달한다. (예를 들어, 원래는 문자로 온걸 int로 바꿔준다.)

     *  주의할 점은 매개변수의 타입이 기본자료형(정수,실수,문자,불린)일 때, 요청파라미터값이 존재하지 않으면 오류가 발생한다. (String타입의 경우에는 null 허용됨)
     *  요청파라미터값을 해당 타입으로 변환할 수 없을 때 오류가 발생한다.


    @RequestParam
      :  요청파라미터값을 요청핸들러의 매개변수와 매핑시키는 어노테이션이다. (값이 있을수도 있고 없을수도 있을 때 사용한다.)
     주요 속성
     *  name : 요청파라미터의 이름을 지정한다.
     *  required : 기본값은 true다. false로 지정하면 name에 지정한 요청파라미터값이 없어도 오류가 발생하지 않는다.
     *  defaultValue : name에 지정한 요청파라미터값이 존재하지 않을 때 매개변수로 대입되는 기본값을 설정한다.
        defaultValue의 값은 문자열로 설정되지만 매개변수에 대입될 때는 해당 타입으로 형변환된다.


     * 요청핸들러 메소드의 매개변수로 가능한 객체 및 어노테이션
     *  HttpServletRequest     요청객체
     *  HttpServletResponse  응답객체
     *  HttpSession                 세션객체
     *  WebRequest                Spring이 제공하는 객체다. 요청객체가 가지고 있는 정보 대부분을 제공하는 객체다.
     *  TimeZone                     시간정보
     *  Locale                          지역정보(국가, 언어)
     *  InputStream                 클라이언트와 연결된 읽기 전용 스트림
     *  OutputStream              클라이언트와 연결된 쓰기 전용 스트림
     *  Reader                         클라이언트와 연결된 텍스트 읽기 전용 스트림
     *  Writer                           클라이언트와 연결된 텍스트 쓰기 전용 스트림

    ---------------------------------------------------------------------------------------------------------------------------------  (주로 아래꺼를 쓴다.)
     *  @RequestParam         요청파라미터와 매개변수를 매핑시키는 어노테이션
     *  @PathVariable             요청 URL 경로에 포함된 파라미터값과 매개변수를 매핑시키는 어노테이션
     *  @ModelAttribute          요청파라미터와 해당값을 저장하는 객체를 매핑시키는 어노테이션(생략도 가능)
     *  @RequestBody            요청메세지의 바디부 정보와 매개변수를 매핑시키는 어노테이션
     *  @Valid                          요청파라미터값의 유효성 여부를 검증시키는 어노테이션
     *  Model                           뷰에 전달할 정보를 저장하는 객체
     *  Errors                           요청파라미터값의 유효성 검증 결과를 저장하는 객체
     *  BindingResult               요청파라미터값의 유효성 검증 결과를 저장하는 객체
     *  SessionStatus              세션에 저장된 정보를 삭제하는 객체
     *  기본자료형                   요청파라미터값을 전달받는다.
     *  String                            요청파라미터값을 전달받는다.
     *  사용자정의 객체           요청파라미터값을 전달받는다.


    요청 URL 매핑하기
     

    요청URL과 요청핸들러 메소드를 매핑시키는 어노테이션
     @RequestMapping : 요청방식에 상관없이 요청 URL을 기준으로 매핑시킨다. 클래스레벨의 URL 매핑, 메소드 레벨의 URL매핑과 더해진다.
     @GetMapping  : 요청방식에 GET 방식이고 요청 URL이 일치하는 요청핸들러 메소드와 매핑시킨다. 
     @PostMapping : 요청방식이 POST 방식이고 요청 URL이 일치하는 요청핸들러 메소드와 매핑시킨다.
     @PutMapping : 요청방식이 PUT 방식이고 요청 URL이 일치하는 요청핸들러 메소드와 매핑시킨다.
     @DeleteMapping : 요청방식이 DELETE 방식이고 요청 URL이 일치하는 요청핸들러 메소드와 매핑시킨다.
       
     요청방식
     *  GET : 서버에서 정보를 조회하는 요청
     *  POST : 서버에 정보를 추가하는 요청
     *  PUT : 서버의 정보를 변경하는 요청
     *  DELETE : 서버의 정보를 삭제하는 요청
     * 일반적인 웹 애플리케이션에서는 GET, POST 두가지 방식을 사용한다.
     * Rest 방식의 웹 애플리케이션에서는 GET, POST, PUT, DELETE 방식을 전부 사용한다.

    - 원래는 위와 같이 url을 적었지만 Rest방식에서는 아래와 같이 url을 적는다. 

    - Rest방식에서는 url에 동작에 대한 정보가 없다. 그대신 어떤 동작을 할 건지 POST, GET, PUT, DELETE를 보고 알 수 있다.


    SessionUtils를 만들어서 사용자정보 전달받기

    SessionUtils를 활용해서 코드를 심플하게 만든다.

    Session은 톰캣이 만드는 인터페이스라서 메소드를 테스트하고 싶을 때 무조건 톰캣이 켜져 있어야 한다는 점이 불편하다.

    그래서 가급적 톰캣이 만드는 객체는 안쓰고 싶은 것이다. 

    그래서 Session을 넣는 코드를 없애고, 클라이언트가 서버에 보내는 값만 남긴다.

    com.sample.utils 패키지에 SessionUtils라는 클래스를 작성해둔다.

    /**
     * HttpSession 객체에 속성을 저장하고, 삭제하는 기능이 제공되는 유틸리티 클래스다.
     * @author lee_e
     *
     */
    public class SessionUtils {
    
    	/**
    	 * 이름하고 값을 전해주면 HttpSession객체에 해당이름으로 속성을 추가한다.
    	 * @param name 속성명
    	 * @param value 속성값(객체)
    	 */
    	public static void setAttribute(String name, Object value) {
    		getRequestAttributes().setAttribute(name, value, RequestAttributes.SCOPE_SESSION);
    	}
    	
    	/**
    	 * HttpSession객체에서 지정된 속성을 삭제한다.
    	 * @param name 속성명
    	 */
    	public static void removeAttribute(String name) {
    		getRequestAttributes().removeAttribute(name, RequestAttributes.SCOPE_SESSION);
    	}
    	
    	/**
    	    * HttpSession 객체에서 지정된 속성을 반환한다.
    	    * @param name 속성명
    	    * @return 속성값(객체)
    	    */
    	   public static Object getAttribute(String name) {
    	      return getRequestAttributes().getAttribute(name, RequestAttributes.SCOPE_SESSION);
    	   }
    	
    	 // RequestAttribute는 세션객체와 Request객체의 속성을 저장하고 가져오는 등의 기능을 제공해준다.
    	private static RequestAttributes getRequestAttributes() {
    		return RequestContextHolder.getRequestAttributes();
    	}
    }

    RequestContextHolder

    : 지금 현재 요청에 대한 요청객체, 세션객체의 속성을 보관하는 저장소 역할

    RequestAttributes

    : 스프링에서 제공해주는 객체, Request의 속성을 조작할 수 있도록 기능을 제공하는 메소드 (HttpSession을 직접 사용하지 않고도 세션의 혹은 요청객체의 속성을 조작할 수 있도록 기능을 제공한다.)

    RequestContextHolder.getRequestAttributes();

    : 지금 현재 요청정보, 세션정보가 들어있는 객체가 반환된다. 요청정보의 속성을 변경할 수 있는 기능을 제공한다.

     

    HttpSession을 사용한 코드
    SessionUtils를 사용한 코드


    자바스크립트의 변수

       var 
        변수의 범위가 함수다.
          function a() {
             var x = 10;
             if (x > 5) {
                var y = 20;
                var z = x*y;
                console.log(x, y, z);   // 10, 20, 200 출력된다.
             }
             console.log(x, y, z);      // 10, 20, 200 출력된다.
          }
          ------------------------------------------------
         변수 호이스팅(변수 끌어올리기)이 적용된다
          function a() {
             console.log(x, y, z); // 오류가 발생하지 않는다 undefined, undefined, undefined가 출력된다.
             var x = 10;
             if (x > 5) {
                var y = 20;
                var z = x*y;
                console.log(x, y, z);   
             }
             console.log(x, y, z);   
          }
          // 자바스크립트 컴파일러는 위의 소스코드를 아래와 같이 변경한다.
          function a() {
             var x, y, z;   // 함수내에서 선언된 모든 변수의 선언을 함수의 첫번째 라인으로 끌어올린다.
             console.log(x, y, z);

             x = 10;
             if (x > 5) {
                y = 20;
                z = x*y;
                console.log(x, y, z);   
             }
             console.log(x, y, z);   
          }
          ---------------------------------------------
          변수명이 중복되어도 오류가 발생하지 않는다.
          function x() {
              var x = 10;
              console.log(x);   // 10이 출력된다.

              var x = 20;
              console.log(x);   // 20이 출력된다.
             }

       let
         변수의 범위가 블록이다.
          function a() {
             let x = 10;
             if (x > 5) {
                let y = 20;
                let z = x*y;
                console.log(x, y, z);   // 10, 20, 200 출력된다.
             }
             console.log(x, y, z);      // 오류 발생, y, z가 변수는 존재하지 않는다.
          }
          --------------------------------------------------
          변수 호이스팅이 적용되지 않는다.
          function a() {
             let x = 10;
             if (x > 5) {
                let y = 20;
                let z = x*y;
                console.log(x, y, z);   // 10, 20, 200 출력된다.
             }
             console.log(x, y, z);      // 오류 발생, y, z가 변수는 존재하지 않는다.
          }
          -------------------------------------------------
          변수명이 중복되면 오류가 발생한다.
          function x() {
              let x = 10;
              console.log(x);

              let x = 20;         // 변수명 중복으로 문법 오류가 발생한다.
              console.log(x);
          }

       const
          한번 할당된 값을 변경할 수 없다.
          const x = 10;
          x = 100;   // 오류가 발생한다. 값을 변경할 수 없다. 


    UserService
    UserController

    Controller와 Service의 구분

    유효성 검증, 메소드를 실행할 자격이 있는지를 확인, 세션에서 사용자정보를 가져오는 것, jsp에 보여주려고 정보를 담는 것, 웹에 가까운 것은 Controller에서 실행  

    db엑세스, 업무로직을 수행하는 건 Service에서 실행

    서비스에서는 표현계층 중립적이어야 한다.

    백엔드에서 표현계층은 프론트엔드와 직접적으로 연관이 있다.

    백엔드의 표현계층은 프런트엔드에서 요청한걸 서비스가 이해할 수 있는 걸로 바꿔서 보내주고,

    서비스에서 받은 걸 프론트엔드가 이해할 수 있는 걸로 바꿔서 전달하는 역할을 한다.


    싱글톤

     

    락앤락 반찬통 객체는 싱글턴이 아니다. 여러개 있으니까. 

    정보를 저장하는 객체는 싱글턴으로 만들지 않는다.

    홍길동과 김유신이 쓰레드를 통해 동시에 메소드를 실행할 수 있는데, dto가 한개 밖에 없으니까 정보를 덮어씌워버린다.그래서 정보를 저장하는 객체는 싱글턴으로 만들지 않는다. 각각 다른 dto가 있어야 한다. 

     

    클래스를 만들 때 메서드가 동시에 실행되는 경우라 해도 메소드끼리 간섭하지 않는다. 메소드 안에 있는 변수는 메소드끼리 완벽하게 분리되어 있다. 메서드 안에 있는 변수는 다른 놈이 절대로 못본다. 그런데 멤버변수는 객체 만들어지면 객체랑 같이 생존하는 변수이다. 메서드의 변수는 메소드가 실행되는 동안 생겼다 사라진다. 멤버변수는 객체가 남아있는 동안 계속 존재한다. 메소드를 통해 멤버변수의 값을 바꿔놓더라도 바꿔놓은 값이 유지될거라는 보장이 없다. 

    그래서 싱글턴객체에서 멤버변수는 항상 Read-only 여야 한다. 멤버변수에 있는 걸 꺼내서 쓰는 것만 된다. 담는건 안됨.

    그래서 UserService에 뭘 담지 않는 것이다. 생성시에만 값을 넣고 그 이후에는 가져오는 작업만 한다.

    쓰레드 safe하다라고 한다.

     

    VO나 DTO는 값을 담을 때마다 새로 만들어야한다. 

    서비스나 Dao는 정보가 저장되어 있지 않고 담고 있는 것은 읽기전용이다. 

    기능이 있는 객체는 하나만 있으면 된다. 멀티쓰레딩으로 엄청 빠른 속도로 작업을 해서 동시에 실행되는 것처럼 보인다.

    정보를 담는 객체는 여러개 있어야 한다.

     

    속성명을 잘못적으면 아예 화면에 표시되지 않고, 변수명을 잘못 적으면 오류가 난다.

    댓글

Designed by Tistory.