내배캠 TIL 27일차

오병택·2025년 3월 26일

내배캠

목록 보기
49/73

학습 요약

Schedule, 그 전에 밀린 TIL 쓰기

Schedule lv1, 2

오늘도 역시 수정한 부분만 짤라서 올려보겠습니다.

ScheduleController클래스

// 전체 일정 조회
    @GetMapping
    public ResponseEntity<List<ScheduleResponseDto>> findAllSchedules(@RequestBody ScheduleRequestDto dto){

        return new ResponseEntity<>(scheduleService.findAllSchedules(dto),HttpStatus.OK);
    }

ScheduleService인터페이스

List<ScheduleResponseDto> findAllSchedules(ScheduleRequestDto dto);

ScheduleServiceImpl클래스

// service) 일정 목록 조회 메서드
    @Override
    public List<ScheduleResponseDto> findAllSchedules(ScheduleRequestDto dto) {
        return scheduleRepository.findAllSchedules(dto.getName(),dto.getModificationdate());
    }

ScheduleRepository인터페이스

List<ScheduleResponseDto> findAllSchedules(String name, String modificationdate);

ScheduleRepositoryImpl클래스

// repository) 일정 목록 조회 메서드
    @Override
    public List<ScheduleResponseDto> findAllSchedules(String name, String modificationdate) {
        if (name==null && modificationdate==null) {
            return jdbcTemplate.query("select * from schedule order by modificationdate desc", scheduleRowMapper());
        }else if (name== null) {
            return jdbcTemplate.query("select * from schedule where modificationdate like ? order by modificationdate desc",
                    scheduleRowMapper(),modificationdate+"%");
        }else if (modificationdate== null) {
            return jdbcTemplate.query("select * from schedule where name=? order by modificationdate desc",
                    scheduleRowMapper(),name);
        }else{
            return jdbcTemplate.query("select * from schedule where name=? and modificationdate like ?" +
                    "order by modificationdate desc", scheduleRowMapper(),name,modificationdate+"%");
        }
    }

ScheduleRequestDto클래스

private String modificationdate;

ScheduleResponseDto클래스

// annotation 삭제
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")  

빼먹은 요구사항

일정 목록 조회
수정일 (형식 : YYYY-MM-DD)
작성자명
조건 중 한 가지만을 충족하거나, 둘 다 충족을 하지 않을 수도, 두 가지를 모두 충족할 수도 있습니다.


Spring 입문 4주차


Spring Annotation 1강

@Slf4j

  • Slf4j는 인터페이스이고 그 구현체로 Logback같은 라이브러리를 선택
  • 실제 개발에서는 Spring Boot가 기본으로 제공하는 Logback을 대부분 사용

Logging

  • Thread 정보, 클래스 이름과 같은 부가 정보를 함께 확인할 수 있음
  • 실제 운영 환경에서는 System.out.println();을 사용하여 Console에 정보를 출력하지 않고, 별도의 로깅 라이브러리를 사용하여 로그를 출력
  • Log Level 설정을 통하여 Error 메세지만 출력하도록 하도록 하기도 하고 로그 메세지를 일자별로 모아서 저장하여 외부 저장소에 보관하기도 함
    • Log Level
      • TRACE > DEBUG > INFO > WARN > ERROR
 # com.example.springbasicannotation 하위 경로들의 로그 레벨을 설정
logging.level.com.example.springbasicannotation=TRACE <-

@Controller VS @RestController

@Controller

Annotation 기반의 Spring에서 Controller(Handler)를 만들 때 사용하는 어노테이션

  • View가 있는 경우에 사용
  • 즉, Template Engine인 Thymeleaf, JSP 등을 사용하는 경우

@RestController

  • 응답할 Data가 있는 경우에 사용
  • 현재는 대부분 @RestController를 사용하여 API가 만들어짐. (Restful API)
  • return 값으로 View를 찾는 것이 아니라 HTTP Message Body에 Data를 입력

Spring Annotation 2강

@Component

  • Spring Bean에 등록하는 역할을 수행
    • Spring Bean은 애플리케이션의 구성 요소를 정의하는 객체
  • @Indexed
    • 클래스가 컴포넌트 스캔의 대상으로 Spring Bean에 더 빠르게 등록되도록 도와줌

@Target

  • @Target 이 선언된 하위 어노테이션이 어떤 범위에 적용되는지 설정

@Retention

  • @Retention 하위의 어노테이션이 얼마나 오래 유지되는지를 결정

RetentionPolicy Enum 속성

  1. SOURCE
    • 소스 코드(.java)에서만 유지.
    • 컴파일러에 의해 클래스 파일로 저장되지 않음
  2. CLASS
    • 컴파일된 클래스 파일(.class)에 저장되지만, JVM이 실행 시 읽지 않음 (주석과 같음)
    • Default 값이다.
  3. RUNTIME
    • 클래스 파일(.class)에 저장되고, JVM에 의해 런타임 시점에 읽을 수 있음
    • 즉, 실제 런타임 시점의 코드에 반영되어 영향을 줌

@Documented

  • Javadoc 등의 문서화 도구에 의해 문서화되어야 함을 나타냄

Request Mapping 1강

@RequestMapping

특정 URL로 Request를 보내면 들어온 요청을 Controller 내부의 특정 Method와 Mapping 하기 위해 사용

Client로부터 요청이 왔을 때 어떤 Controller가 호출될지 Mapping하는 것은 단순히 URL로 Mapping 하는 것이 아니라 여러가지 요소(URL, Method 등)를 조합하여 Mapping함

  1. Spring Boot 3.0 버전 이하
    • URL path /example, /example/ 모두 허용(Mapping)
  2. Spring Boot 3.0 버전 이상(현재 버전)
    • URL path /example 만 허용(Mapping)
  3. 속성값들을 설정할 때 배열 형태로 다중 설정이 가능
    ex) @RequestMapping({”/example”, “/example2”, “/example3”})
  4. HTTP Method POST, GET, PUT, PATCH, DELETE, HEAD 모두 허용
  5. method 속성으로 HTTP 메서드를 지정하면 지정된것만 허용
package com.example.springbasicannotation.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

// 응답 데이터를 반환한다.
@RestController
public class RequestMappingController {

    // HTTP Method 는 GET만 허용한다.
    @RequestMapping(value = "/v1", method = RequestMethod.GET)
    public String exampleV1() {
        // logic
        return "this is sparta!";
    }

}

@GetMapping

  • 내부적으로 @RequestMapping(method = RequestMethod.GET) 을 사용
  • @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping도 같음

❓그럼 실제로는 위 어노테이션들만 사용하고 @RequestMapping은 사용하지 않나요?
위 어노테이션들은 메서드 레벨에서만 가능하지만, @RequestMapping은 클래스 레벨에서도 가능
그래서 @RequestMapping는 prefix로 선언할 URL을 class 레벨에 적용하는 것에 주로 사용

@PathVariable

  • HTTP 특성 중 하나인 비연결성을 극복하여 데이터를 전달하기 위한 방법 중 하나
  • URL로 전달된 값을 파라미터로 받아오는 역할을 수행
  1. 경로 변수를 중괄호에 둘러싸인 값으로 사용할 수 있음

ex) user/{id}

  1. 기본적으로 @PathVariable로 설정된 경로 변수는 반드시 값을 가져야 하며 값이 없으면 응답 상태코드 404 Not Found Error가 발생
  2. 최근 Restful API를 설계하는 것이 API의 기준이 되며 해당 어노테이션의 사용 빈도가 높아짐

@PathVariable 규칙

  1. 파라미터 변수명과 PathVariable 변수명이 같으면 속성 값 생략 가능
@RequestMapping("/posts")
@RestController
public class PathVariableController {
	
	// postId로 된 post 단건 조회
	@GetMapping("/{postId}")
    
    // @PathVariable("postId") Long data -> @PathVariable Long postId로 생략 가능
	public String pathVariableV1(@PathVariable("postId") Long data) {
    
		// logic 
		String result = "PathvariableV1 결과입니다 : " + data;
		return result;
	}
}
  1. @PathVariable 다중 사용 가능

Request Mapping 2강

특정 파라미터 매핑

속성 설정을 통하여 특정 헤더, 특정 파라미터와 Mapping 할 수 있음

1. Parameter 추가 매핑

  • 특정 파라미터와 매핑하는 방법
package com.example.springbasicannotation.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ParameterController {

    // parms 속성값 추가
    @GetMapping(value = "/users", params = "gender=man")
    public String params() {
        // logic
        String result = "params API가 호출 되었습니다.";
        return result;
    }

}

속성 작성 규칙
1. params = "gender"
- params의 key값은 커스텀이 가능
- value는 없어도 됨
2. params = "!gender"
- gender가 없어야 함
3. params = "gender=man"
- gender=man 이어야 함
4. params = "gender!=man"
- params의 value값이 man가 아니여야 함
5. params = {"gender=man", "gender=woman"}
- 배열로 속성 값을 여러 개 설정이 가능

2. 특정 Header 매핑

  • 특정 Header와 매핑하는 방법
@RestController
public class ParameterController {
	
	// headers 속성값 추가
  @PostMapping(value = "/users", headers = "Content-Type=application/json")
  public String headers() {
      // logic
      String result = "headers API가 호출 되었습니다.";
      return result;
  }
  
}

3. MediaType 매핑, consume(수용)

HTTP Header Content-Type(요청)과 매핑

@RestController
public class ParameterController {
	
	// consumes 속성값 추가
  @PostMapping(value = "/users", consumes = "application/json") // MediaType.APPLICATION_JSON_VALUE
  public String consumes() {
      // logic
      String result = "consumes API가 호출 되었습니다.";
      return result;
  }
	
}
  • 속성 작성 방법
    1. consumes=”application/json”
      • application/json 미디어 타입 허용
    2. consumes=”!application/json”
      • application/json 제외 미디어 타입 허용
    3. consumes=”application/*”
      • application/ 으로 시작하는 모든 미디어 타입 허용
    4. consumes=”*\/*”
      • 모두 허용

4. MediaType 매핑 produces(제공)

  • 요청 헤더의 Accept 값에 따라서 produces 하는 값이 변함
@RestController
public class ParameterController {
	
	// produces 속성값 추가
  @GetMapping(value = "/users", produces = "text/plain")
  public String produces() {
      // logic
      String result = "text/plain 데이터 응답";
      return result;
  }	
}
  • HTTP 요청 Accept Header에 Media Type이 있어야 함
  • consumes 속성 사용법과 같음

MediaType 종류

  • HTTP 헤더 조회
    • Spring에서 요청 Header에 쉽게 접근할 수 있음
      • HttpServletRequest와 같이 파라미터로 다룰 수 있음
    • Controller 예시
// 로깅
@Slf4j
@RestController
public class RequestHeaderController {

    @GetMapping("/request/headers")
    public String headers(
            HttpServletRequest request, // Servlet에서 사용한것과 같음
            HttpServletResponse response, // Servlet에서 사용한것과 같음
            @RequestHeader MultiValueMap<String, String> headerMap,
            @RequestHeader("host") String host,
            @CookieValue(value = "cookie", required = false) String cookie,
            HttpMethod httpMethod,
            Locale locale
    ) {
		    // Servlet
        log.info("request={}", request);
        log.info("response={}", response);
        
        // @RequestHeader
        log.info("headerMap={}", headerMap);
        log.info("host={}", host);
        
        // @CookieValue
        log.info("cookie={}", cookie);
        
        // HttpMethod
        log.info("httpMethod={}", httpMethod);
        
        // Locale
        log.info("Locale={}", locale);

        return "success";
    }
}

Log 출력 결과

MultiValueMap

Map과 유사하게 Key, Value 형식으로 구현되어 있지만 하나의 Key가 여러 Value를 가질 수 있다 HTTP Header, Reqeust Parameter와 같이 하나의 Key에 여러 값을 받을 때 사용
ex) key1=value1&key1=value2

느낀 점

위의 요구사항으로 조회를 하라는 부분을 다른 식으로 이해하고 작성한 것을 사실 어제 다 만들었다고 생각했는데 팀장님이 이거 구현하셨어요?라는 말에 등골이 오싹해졌다. 이 말을 들은 시각은 대략 11시.. 급하게 수정하고 주석 처리도 같이 하고 api도 다시 써야 하고 read.me도 수정해야 해서 완전 집중해서 최대한 빠르게 만들어서 1시쯤에 제출 완료했다. 😎
결론 : 시간이 사라짐. 좋은 건가?🤔
그리고 오랜만에 밀린 TIL 쓰면서 다시 보니까 더 이해가 되는 것 같아서 좋다. 😁

profile
걱정하지 말고 일단 해봐!

0개의 댓글