Memo: 정리할 것들

    Memo: 정리할 것들

    2022, Aug 10    
    • Kramdown table of contents

    View Template

    CSRdf

    SSR

    JSP

    • RedirectView
      /*
        리다이렉트 할 때 모델객체를 넘겨야 할 경우가 있다.
        아래와 같이 @RequestParam 받는 인자도 있고, 메서드에서 셋업하는 경우처럼 혼재되어 있는 경우인데
        각설하고 아래의 경우는 RedirectView 왜 썼는지 모르겠다.
        ++ 아마도 jsp 와 vue.js 의 동시 사용으로 인한 model object 를 받아서 처리하기 싫었던 것으로 보여짐.
        요청파라미터가 추가되면서 더 탁해진 듯 하다.
      */
    	@GetMapping("/getUrl")
    	public RedirectView getMethodName(@RequestParam(value = "reqParam", required = false)
    											   boolean reqParam, RedirectAttributes redirectAttributes) {
    		RedirectView redirectView = new RedirectView("/redirectUrl?parameter=parameterValue", true);
    		redirectAttributes.addFlashAttribute("reqParam", reqParam);
    		return redirectView;
    	}
    
      /*
        이것과 뭐가 다름? 리다이렉트를 쓴 이유를 알 수 없음.
        http status 302 까지 보여주며 어떤 특정 상황임을 인지시키고 다른 곳으로 보내려는 의도가 있어야하는데
        저건 다른 곳으로 보내는게 아니라 종착점이 정해져 있잖슴. 차라리 modelandview가 낫다.
      */
    	@GetMapping("/getUrl")
    	public ModelAndView getMethodName(@RequestParam(value = "reqParam", required = false)
    											   boolean reqParam) {
        ModelAndView mav = new ModelAndView("/redirectUrl", true);
        mav.addObject("parameter","parameterValue");
        mav.addObject("reqParam",reqParam);
    		return mav;
    	}
    

    ModelAndView

    Thymeleaf(view) - todo

    • Thymeleaf 시작하기

    html 태그에 다음과 같은 url을 입력하여 th 명령어를 활성화하도록 하자~

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
      <head>
        ...
      </head>
    </html>
    

    <p th:text="${model}">word</p>

    model에 data key-value로 담아 타임리프 뷰 템플릿이 렌더링될 때 아래 태그는 emptydata에 바인딩된 값 something로 치환한다.

    ...
    <body>
    <p th:text="${data}">empty</p>
    </body>
    </html>
    
    결과 : <p>something</p>
    
    • SpringEL 표현식
    Object
    ${user.username} = userA
    ${user['username']} = userA
    ${user.getUsername()} = userA
    
    List
    ${users[0].username} = userA
    ${users[0]['username']} = userA
    ${users[0].getUsername()} = userA
    
    Map
    ${userMap['userA'].username} = userA
    ${userMap['userA']['username']} = userA
    ${userMap['userA'].getUsername()} = userA
    

    Programming Language

    Java

    Instance, Constructor

    Application Structure

    여러가지 애플리케이션 구조가 있으나 가장 단순하면서 많이 쓰이는 방법은 역할에 따라 3가지 계층으로 나누는 것

    • Presentation Layer
      • ui와 관련된 처리 담당
      • 사용자 요청 검증
      • 주 사용 기술 : Servlet, HTTP 같은 웹기술, SpringMVC
    • Service Layer
      • 비즈니스 로직 담당
      • 주 사용 기술 : 가급적 특정 기술에 종속적이지 않고 순수자바 지향
    • Repository Layer
      • 실제 데이터베이스에 접근하는 코드
      • 주 사용기술 : JDBC, JPA, File, Redis, Mongo…,

    AtomicLong(java) - todo

    멀티쓰레드 환경에서 동시에 다수가 접근할 경우 데이터의 정합성을 보장할 수 없다.
    그래서 위와 같은 상황에 long 타입을 사용해야 한다면 AtomicLong 을 고려하라고~ 정리할 것

    ConcurrentHashMap(java) - todo

    AtomicLong 과 같은 이유임. 정리하셈

    Inner Class (Java) - todo


    FrameWork

    Spring

    log

    BindingResult

    스프링이 제공하는 검증 오류를 보관하는 객체이다. 검증 오류가 발생하면 여기에 보관하면 된다. BindingResult 가 있으면 @ModelAttribute 에 데이터 바인딩 시 오류가 발생해도 컨트롤러가 호출된다!

    • 예) @ModelAttribute에 바인딩 시 타입 오류가 발생하면?

      • BindingResult 가 없으면 400 오류가 발생하면서 컨트롤러가 호출되지 않고, 오류 페이지로 이동한다.
      • BindingResult 가 있으면 오류 정보( FieldError )를 BindingResult 에 담아서 컨트롤러를 정상 호출한다.
    • BindingResult에 검증 오류를 적용하는 3가지 방법
      • @ModelAttribute 의 객체에 타입 오류 등으로 바인딩이 실패하는 경우 스프링이 FieldError 생성해서 BindingResult 에 넣어준다.
      • 개발자가 직접 넣어준다.
      • Validator 사용 이것은 뒤에서 설명
    • 타입 오류 확인
      숫자가 입력되어야 할 곳에 문자를 입력해서 타입을 다르게 해서 BindingResult 를 호출하고 bindingResult 의 값을 확인해보자.
    • 주의
      • BindingResult 는 검증할 대상 바로 다음에 와야한다. 순서가 중요하다. 예를 들어서 @ModelAttribute Item item , 바로 다음에 BindingResult 가 와야 한다.
      • BindingResult 는 Model에 자동으로 포함된다.

    Test Stub

    꽁초,그루터기 등 마치 잔여물 같은 느낌의 단어를 연상캐한다. 나름의 해석을 하자면 협업 간 필요 구현체가 미구현된 경우, 더미 객체를 활용하여 현재 구현부의 테스트를 진행할 수 있도록 해주는 것.

    • Mockito 의 Stub Method
      • doReturn()
      • doNothing()
      • doThrow()

    웹 프로젝트(spring) - todo

    • 프로젝트 생성
      • project : gradle
      • Language : java
      • spring boot : 2.7
      • meta data
        • group : xxx
        • artifact : yyy
        • name : yyy
        • package name : group.artifact(=name) *기호제외
        • packaging : Jar
        • java : 11
      • dependencies
        • spring web
        • thymeleaf
        • lombok
    • 프로젝트 설계
      • domain

        화면, 기술, ui, 인프라 등의 영역을 제외한 핵심 비즈니스 업무 영역을 의미한다.
        web은 domain을 의존하지만 domain은 web을 의존하지 않도록 설계해야 함.
        예를 들어, web package를 전부 삭제해도 domain에는 영향이 없도록 의존설계를 해야 한다.

        • item
        • member
        • login
      • web
        • item
        • member
        • login

    spring message (spring) - todo

    request and response data type setting (spring) - todo

    요청에 의해 소모(consumes)해야 하는 데이터의 타입을 강제할 수 있다.

    // 아래와 같이 json 타입을 강제하면 uri를 호출하는 요청자는 헤더의 데이터 타입을 명시해야한다.
    // Content-Type : application/json
    @PostMapping(value="/test", consumes = MediaType.APPLICATION_JSON_VALUE)
    public void test(@RequestBody Something something){
      // ...
    }
    

    요청에 의한 반환할 생성(produces) 데이터를 정의하는 경우

    // 요청자는 반환되는 데이터의 타입을 헤더에 정의하여 요청할 수 있다.
    // Accept:application/json
    @ResponseBody
    @PostMapping(value="/test", produces = MediaType.APPLICATION_JSON_VALUE)
    public void test(@RequestBody Something something){
      // ...
    }
    

    Annotation

    Spring Annotation(spring) - todo

    • @ModelAttribute
      • 해당 어노테이션을 선언하면 데이터 객체의 값을 Model 객체에 자동으로 담아준다.
    • @RequestParam
      • HttpServletRequest 로 가져오던 parameter 정보를 @RequestParam variableName 으로 가져올 수 있음
    • @RequestBody
      • 위의 어노테이션들과 달리 json 데이터인 경우 반드시 명시해야 함. 생략할 수 없음.

    Lombok Annotaion(spring) - todo

    • @Getter/Setter
      • 프로퍼티를 필드에 선언하면 접근자/설정자(getOOO/setOOO)를 자동생성 해준다. (boolean 의 경우 isOOO 형식임)
    • @ToString
      • toString 메서드를 자동생성해줌. 제외해야할 필드가 있다면 exclude에 명시해주면 된다.
        @ToString(exclude = "password")
    • @EqualsAndHashCode

      • 자바 빈을 만들 때 equals와 hashCode 메소드를 자주 오버라이딩 하는데
        @EqualsAndHashCode 어노테이션을 사용하면 자동생성
      /*
        callSuper 속성을 통해 equals와 hashCode 메소드 자동 생성 시 부모 클래스의 필드까지 감안할지 안 할지에 대해서 설정할 수 있습니다.
        즉, callSuper = true로 설정하면 부모 클래스 필드 값들도 동일한지 체크하며,
        callSuper = false로 설정(기본값)하면 자신 클래스의 필드 값들만 고려합니다.
      */
      //domain layer
      @EqualsAndHashCode(callSuper = true)
        public class User extends Domain {
        private String username;
        private String password;
      }
      //service layer
      User user1 = new User();
      user1.setId(1L);
      user1.setUsername("user");
      user1.setPassword("pass");
      
      User user2 = new User();
      user1.setId(2L); // 부모 클래스의 필드가 다름
      user2.setUsername("user");
      user2.setPassword("pass");
      
      user1.equals(user2);
      // callSuper = true 이면 false, callSuper = false 이면 true
      
    • @NoArgsConstructor
      • 파라미터가 없는 기본 생성자를 생성
    • @AllArgsConstructor
      • 모든 필드값을 파라미터로 받는 생성자를 생성
    • @RequiredArgsContructor
      • 이녀석은 final 또는 @NonNull 필드만을 대상으로 생성자를 생성함. 객체의 의존성 주입을 생성자를 따로 작성하지 않아도 자동주입해줌
    • @Data
      • @Data는 위의 @Getter, @Setter, @RequiredArgsConstructor, @ToString, @EqualsAndHashCode을 한꺼번에 설정해주는 매우 유용한 어노테이션

    Jackson Annotaition - todo

    • @JsonInclude

      json 형식으로 데이터를 주고받을 때 Jackson의 ObjectMapper를 자주 이용한다.
      그런데 기본값으로 Serialize 하게 되면 null, “” 같은 (상황에 따라) 필요 없는 값 또한 모두 변환시켜준다.
      이를 아래의 메소드를 통하여 Serialize할 때 원하는 값만을 포함시킬 수 있다.

      @Getter
      //@JsonInclude(JsonInclude.Include.원하는타입)
      public static class Value {
          private String string;
          private String emptyString;
          private Object nullValue;
          private int number;
          private int zero;
          private List<String> list;
          private List<String> emptyList;
          private Date date;
          private Date zeroDate;
          private Optional<String> optional;
          private Optional<String> emptyOptional;
      
      
          public Value() {
              this.string = "민수";
              this.emptyString = "";
              this.nullValue = null;
              this.number = 100;
              this.zero = 0;
              this.list = asList("민수", "원우");
              this.emptyList = emptyList();
              date = new Date();
              zeroDate = new Date(0L);
              this.optional = Optional.of("민수");
              this.emptyOptional = Optional.empty();
          }
      }
      
      • ALWAYS (기본값) : 모든 값을 출력
      @Test
      public void always() throws JsonProcessingException {
          this.objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
          String result = this.objectMapper.writeValueAsString(new Value());
      
          System.out.println(result);
      }
      //결과
      {
        "string": "민수",
        "emptyString": "",
        "nullValue": null,
        "number": 100,
        "zero": 0,
        "list": [
          "민수",
          "원우"
        ],
        "emptyList": [],
        "date": 1527077763796,
        "zeroDate": 0,
        "optional": {
          "present": true
        },
        "emptyOptional": {
          "present": false
        }
      }
      
      • NON_NULL : null은 제외한다.
      @Test
      public void non_null() throws JsonProcessingException {
          this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
          String result = this.objectMapper.writeValueAsString(new Value());
      
          System.out.println(result);
      }
      //결과
      {
        "string": "민수",
        "emptyString": "",
        "number": 100,
        "zero": 0,
        "list": [
          "민수",
          "원우"
        ],
        "emptyList": [
        ],
        "date": 1527077763837,
        "zeroDate": 0,
        "optional": {
          "present": true
        },
        "emptyOptional": {
          "present": false
        }
      }
      
      • NON_ABSENT : null 제외, 참조 유형(‘Optional’ 또는 {link java.utl.concurrent.atomic.AtomicReference})의
        absent값; 즉, null이 아닌 값은 제외한다.
      @Test
      public void non_absent() throws JsonProcessingException {
          this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_ABSENT);
          String result = this.objectMapper.writeValueAsString(new Value());
      
          System.out.println(result);
      }
      //결과
      {
        "string": "민수",
        "emptyString": "",
        "number": 100,
        "zero": 0,
        "list": [
          "민수",
          "원우"
        ],
        "emptyList": [
        ],
        "date": 1527077763833,
        "zeroDate": 0,
        "optional": {
          "present": true
        },
        "emptyOptional": {
          "present": false
        }
      }
      
    • NON_EMPTY :

      null은 제외한다.
      absent는 제외한다. ( 3. NON_ABSENT 참고 )
      Collection, Map의 isEmpty()가 true 이면 제외한다.
      Array의 length가 0이면 제외한다.
      String의 length()가 0이면 제외한다.

    @Test
    public void non_empty() throws JsonProcessingException {
        this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        String result = this.objectMapper.writeValueAsString(new Value());
    
        System.out.println(result);
    }
    //결과
    {
      "string": "민수",
      "number": 100,
      "zero": 0,
      "list": [
        "민수",
        "원우"
      ],
      "date": 1527077763822,
      "zeroDate": 0,
      "optional": {
        "present": true
      },
      "emptyOptional": {
        "present": false
      }
    }
    
    • NON_DEFAULT :

      empty는 제외된다. ( 4. NON_EMPTY 참고 )
      primitive 타입이 디폴트 값이면 제외한다. (int / Integer : 0 , boolean / Boolean : false 등)
      Date의 timestamp가 0L이면 제외한다.

    @Test
    public void non_default() throws JsonProcessingException {
        this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
        String result = this.objectMapper.writeValueAsString(new Value());
    
        System.out.println(result);
    }
    //결과
    {
      "string": "민수",
      "number": 100,
      "list": [
        "민수",
        "원우"
      ],
      "date": 1527077763725,
      "optional": {
        "present": true
      },
      "emptyOptional": {
      }
    }
    

    Javascript

    vue

    ref 는 input 에만 해당한돠…?

    apply, call

    payload assign

      data() {
        return {
          pamram0:'',
          pamram1:'',
          pamram2:'',
          pamram3:'',
          pamram4:'',
          pamram5:'',
          pamram6:'',
        }
      },
      var payload = this; //이거슨 안될 말이야.
      var payload = Object.assign({}, this.$data) //proxy 떼버리고 object wrapping
    

    mocha unit framework

    SpringEL

    ?. (=Safe Navigation Operator)

    스프링의 SpringEL이 제공하는 문법 중 하나. 만약 여기에서 errors 가 null 이라면 어떻게 될까? 최초 등록폼에 진입한 시점에는 validation에 의한 errors가 없다. 따라서 errors.containsKey() 를 호출하는 순간 NullPointerException 이 발생한다. (errors?. 에서 ? 를 떼면 null. 처럼 표현할 수 있기 때문에 NPE 발생. 치명적이돠) errors?. 은 errors 가 null 일때 NullPointerException 이 발생하는 대신, null 을 반환하는 문법이다. th:if 에서 null 은 실패로 처리되므로 오류 메시지가 출력되지 않는다.

    <div th:if="${errors?.containsKey('globalError')}">
      <p class="field-error" th:text="${errors['globalError']}">전체 오류 메시지</p>
    </div>
    

    Json

    • JSON.stringify(data)

    Tool

    software

    맥북 스포트라이트 점유율문제(Tool) - end

    않이, 어제 갑자기 쿨링팬이 돌길래 활성모니터로 상태를 봤더니 점유율이 굉장히 높은 녀석이 있는게 아니겠음?

    확인해 보니 스포트라이트 관련된 녀석인데 돌지 말라고 꺼버림!

    sudo mdutil -a -i off
    

    그러면 스포트라이트 안쓰냐고? 그래서 알프레드 쓰기로 함^.^

    인텔리제이 properties 한글깨짐현상 (tool) - todo

    인텔리제이를 사용하다 보면 한글깨짐이 생기는 현상이 있다. 요것을 해결하는 방법

    • properties 파일 내 한글깨짐현상
      • prefernce -> File Encodings -> properties files : UTF-8, Transparent native-to-ascii conversion 체크

    맥 기본 설정 (Tool) - todo

    내 입맛에 맞춘 나의 방식이야🤣

    • 터치패드
      • 터치패드 - 세 손가락 드래그
      • 터치패드 - 탭하여 클릭
    • 키보드
      • 키보드 입력, 지연 딜레이 최소화
      • 키보드 - 입력소스 - 두벌식(한글) - 삭제방식 : 글자
      • 키보드 - 텍스트 - 우측 체크박스 해제

    DB

    프로시져(procedure)

    프로시저는 개인적으로 별로 좋아하는 편은 아닌데 그래도 아직 쓰이는 곳들이 있으니까..

    • IF ELSE
    CREATE
        DEFINER = ROOT@`%` PROCEDURE SP_DELETEMEM(IN PARAM VARCHAR(1000))
    BEGIN
    	DECLARE DECLARE_PARAM VARCHAR(1000);
        IF
          EXISTS (SELECT 1 FROM TEST1 WHERE CONDITION = PARAM)
        THEN
            UPDATE TEST2
            SET CONDITION = NULL
            WHERE CONDITION= PARAM;
        ELSE
            UPDATE TEST3
            SET CONDITION = NULL
            WHERE CONDITION = PARAM;
        END IF;
    END;
    

    MARIADB (DB) - TODO

    • WITH RECURSIVE 문 (todo : with 과 비교해서 작성)
      • 메모리 상에 가상의 테이블을 저장
      • 재귀 쿼리를 이용, 실제 테이블을 생성 또는 데이터 Insert 없이 가상 테이블 생성가능
        //설명
        WITH RECURSIVE 테이블명 AS(
        SELECT 초기값 AS 컬럼별명
        UNION ALL
        SELECT 컬럼별명 계산식 FROM 테이블명 WHERE 제어문
        )
        //예시 : h(컬럼) 초기값 1부터 제어문에 합당하는 5까지의 데이터를 갖는 가상테이블 생성
        WITH RECURSIVE CTE AS(
        SELECT 1 AS h
        UNION ALL
        SELECT h+1 FROM CTE WHERE <5
        )
        SELECT * FROM CTE;
        
    • IFNULL
      • IFNULL(exp1, exp2)
        • 순차적 체크
        • exp1가 null이 아니면 exp1 반환
          mysql> SELECT IFNULL(1,0);
            -> 1
          mysql> SELECT IFNULL(NULL,10);
            -> 10
          mysql> SELECT IFNULL(1/0,10);
            -> 10
          mysql> SELECT IFNULL(1/0,'yes');
            -> 'yes'
          

    Documents (doc) - todo

    공식 문서들 정리

    HTML Form (HTTP) - todo

    HTML Form 전송은 PUT, PATCH를 지원하지 않는다.
    GET, POST만 사용할 수 있음. 정리할 것.

    PRG[POST/Redirect/GET] (HTTP) - todo

    TLD:Tag Library Description (Servlet/JSP) - todo

    Abbreviations

    github, gitlab 등 일반적으로도 쓰이지만 개발자들에게 잘 쓰이는 약어.

    • AFAIK - “As Far As I Know”

      • 내가 아는 한.
    • FYI - “For Your Information”

      • 참고로 라는 뜻. 웹상에서 마음에 드는 기사 나 뉴스가 보일때 , FYI라는 말과 함께 링크 URL을 보낼 때 등에 자주 사용된다.
    • GOTCHA - “I’ve Got You”

      • i got it, Got it 과 같은 뜻으로 사용되며, 해냈다! 혹은 알았다로 해석.
    • IMO (IMHO) - “In My (Humble) Opinion”

      • 개인적인 의견 입니다만, 내 소견이지만. (humble 이 들어가면 조금 겸손한 느낌)
    • LGTM - “Looks Good To Me”

      • okay, 개발 한 시스템과 코드 리뷰를 부탁하거나, 자료의 요약을 확인 갔을 때 특별한 문제가없는 경우에 사용함.
    • SSIA - “Subject Says It All”

      • 타이틀이 전부 말해주고 있다. 타이틀만 봐도 이해할 수 있다란 뜻. 이메일 등에서 “Subject and Screenshot Says It All(SSSIA)”로도 쓰임.
    • TBD - “To Be Determined”

      • 결정되지 않은 부분에 “나중에 결정할 것”이라고 말했다 뉘앙스.
    • TGIF - “Thank God, It’s Friday”

      • 불금!
    • TIA - “Thanks In Advance”

      • 한국말로 해석하기 어려움. 힘들겠지만, 잘부탁해 란 뜻으로 상대방 동의없이 “해줄꺼지?”란 의미가 조금 포함되어있음. 따라서 상대와 상황에 따라 실례가 될 수 있으니 잘사용할것.
    • TL;DR. - “Too Long. Didn’t Read”

      • 장문의 시작 부분에 “장문이므로 요약 올립니다”라는 느낌으로 사용.
    • WFM - “Works For Me”

      • 나에게 좋다는 의미로 사용. 시스템의 프로토 타입을 만들어 테스트 할 때, 자신의 환경에서 잘 움직일 때, 또는 의견 조정시에 나에게 고마운 제안이있을 때 등에 사용됨.

    Regex

    Table 찾기

    테이블을 찾는 정규식

    (into|from|join)\s+`?member`?
    
    결과
    from member m
    join member m
    into member m
    
    그럼 전체 replace 를 어떻게 하냐?
    괄호로 감싸진 것은 그룹핑을 의미하는데 이 그룹핑을 활용해서 replace 를 할 수 있다.
    
    $1 user 이렇게 바꾸면 테이블을 표현하는 prefix 는 영향없이 테이블명만 바뀐다.
    결과
    from user
    join user
    
    참고로 백틱과 ? 는 찾을 키워드를 감싸는 경우에만 쓰이는데 이를 위해 ? 를 사용한다.