[231005] @Component, @Autowired, ajax, jackson

MJ·2023년 10월 19일

수업 TIL🐣💚

목록 보기
57/68

이제 대충쓰자

1교시

어제 8교시 복습 생략

@Component

  • @Component로 BoardDao boardDao를 spring container에 넣기 = 클래스 위치에 @Component 붙이면 끝
  • 컴포넌트가 정상 동작하기 위해서는 component-scan(컴포넌트를 찾는 위치)이 지정되어 있어야 한다
  • 예를 들면 servlet-context.xml에 있는 이거. 지정해준 패키지 안에 있는 모든 컴포넌트는 @Component 가능해짐
    <context:component-scan base-package="com.gdu.app05" />

@Autowired로 가져오기


필드, 생성자, setter에 붙일 수 있다. 셋 중 하나 선택해서 하면 됨

@Component 종류

위의 @Component 부분 코드 이렇게 쓸 수도 있다

@Repository  // DAO 전용 @Component, BoardDao boardDao 객체를 Spring Container에 생성해 둔다.
public class BoardDao {
  
  public List<BoardDto> getBoardList() {
    return Arrays.asList(
      new BoardDto("제목1", "작성자1"),
      new BoardDto("제목2", "작성자2"),
      new BoardDto("제목3", "작성자3")
    );
  }

이렇게 전용 컴포넌트들이 있음
대표적으로

  • @Repository : DAO 전용 @Component
  • @Service : 서비스 계층(Business Layer) 전용 @Component
  • @Controller : 컨트롤러 전용 @Component

2교시

가장 많이 쓰는 @Autowired

  • @Autowired로 가져오는 세가지 방법 중 가장 많이 쓰이는 건 뭘까.
    ==> 생성자를 사용하는 방법임.
  • 이유) 필드 만들 때 주입된 객체의 변경 방지를 위해서 final처리를 하게됨.
    final 처리하면 필드 직접 주입은 컴파일 에러, setter처럼 변조되는거는 final이 변조 불가능하게 하려고 지정해준거기 때문에 당연히 불가능하게 되고 그래서 생성자를 사용하는 방법만 남게 되는거임
  • 생성자는 생성하면서 값을 주입하는 메소드이므로 setter와 같은 변조 문제가 발생하지 않음.
    즉, 주조합은 final 필드 + 생성자에 @Autowired
  // 주입된 boardService 객체의 변경 방지를 위해 final 처리한다.
  private final BoardService boardService;
  
  // boardService에 final 처리를 하면 생성자 주입만 가능하다.(필드 주입과 Setter 주입은 불가능하다.)
  // 생성자 주입의 @Autowired는 생략할 수 있으므로 @RequiredArgsConstructor와 같은 Annotation으로 대체할 수 있다.
  @Autowired
  public BoardController(BoardService boardService) {
    super();
    this.boardService = boardService;
  }
  • 생성자는 롬복으로 대체 가능하고 또 @Autowired를 생략해줘도 되므로 @Autowired가 안보여도 롬복 달아준 것만으로도 동작하고 있을 수 있다. 자동주입된 상태임.
  • final 필드 전용 @AllArgsConstructor = @RequiredArgsConstructor
@RequiredArgsConstructor  // final field 전용 생성자
                          // @Autowired를 이용한 생성자 주입을 위해서 추가한다.

@Service  // 서비스 계층(Business Layer) 전용 @Component, Spring Container에 BoardService boardServiceImpl 객체를 생성해 둔다.
public class BoardServiceImpl implements BoardService {
  
  // 주입된 boardDao 객체의 변경 방지를 위해 final 처리한다.
  private final BoardDao boardDao;

  @Override
  public List<BoardDto> getBoardList() {
    return boardDao.getBoardList();
  }

}

6장 만들기


3교시

config 연습을 해보겠다

  • @Configuration + @Bean
  • config : bean 생성 역할 수행할 클래스
@Configuration
public class BoardConfig {
  @Bean
  public BoardDto boardDto1() {  // <bean class="BoardDto" id="boardDto1" />
    return new BoardDto(1, "제목1", "작성자1");
  }
  @Bean
  public BoardDto boardDto2() {  // <bean class="BoardDto" id="boardDto2" />
    return new BoardDto(2, "제목2", "작성자2");
  }
  @Bean
  public BoardDto boardDto3() {  // <bean class="BoardDto" id="boardDto3" />
    return new BoardDto(3, "제목3", "작성자3");
  }
  @Bean
  public BoardDao boardDao() {
    return new BoardDao();
  }
  @Bean
  public IBoardService iBoardService() {
    return new BoardServiceImpl();
  }
  
}  

메소드 이름 boardDto1이 bean의 이름(id)
리턴 타입 BoardDto가 bean의 클래스 타입(class)


bean 만들어졌으니 가지고 와서 넣으면 된다.
타입이 BoardDto로 같은게 3개나 있기 때문에 이름이 같아야 주입될 수 있다

새로운 내용 없어서 생략


4교시

3장 MvcController03에서
모든 @RequestMapping 주소에 /blog가 공통포함되어있었는데 이럴땐 위로 빼주면 공통으로 적용된다.

@RequestMapping("/blog") // /blog로 시작하는 요청을 처리하는 컨트롤러, 모든 메소드의 요청에 "/blog"가 자동삽입
@Controller                               
public class MyController03 {

  @RequestMapping("/detail.do") // GET 방식의 method는 생략 가능. value만 작성할 땐 value= 부분도 생략 가능
  public String blogDetail(HttpServletRequest request, Model model) {
    String blogNo = request.getParameter("blogNo");
    model.addAttribute("blogNo",blogNo);
    return "blog/detail"; // /WEB-INF/views//blog/detail.jsp로 forward한다 (스프링에서는 뭐라고 말 없으면 forward)
  }

   @RequestMapping("/detail.do")
  public String blogDetail2(@RequestParam(value = "blogNo", required = false, defaultValue = "1") int blogNo, Model model) { 
    //@RequestParam(value = "blogNo") int blogNo은 int blogNo로만 써도 됨 (@RequestParam은 생략가능하니까)
    model.addAttribute("blogNo",blogNo);
    return "blog/detail";
  }
  
  @RequestMapping("/detail.do")
  public String blogDetail3(BlogDto dto) { // Model에 저장된 이름은 dto가 아니라 blogDto
    return "blog/detail";
  }
  
  @RequestMapping("/detail.do")
  public String blogDetail4(@ModelAttribute("dto") BlogDto blogDto) {  // Model에 저장되는 이름은 dto 이다. 
    return "blog/detail";
  }

}

원래는 각 매핑주소마다 /blog/가 있었다


5교시 ajax

7장추가했음

maven repository

Jackson Databind
2.15.2
-> pom.xml dependency에 추가

잭슨 = 스프링에서 가장 많이 사용하는 라이브러리, json을 안만들어도됨. 객체, 맵, 리스트 등 만들어서 넘기면 잭슨이 받아서 다 해준다고 함

이 뒤로는 열심히 파일들 만들기했음


6교시

jackson

잭슨 이용하면 json 안 만들어도된다.

리스트 반환해보기. string 이외의 반환 처음해보는 것이다. 원래는 json 직접 만들고 string으로 반환했었음.

ajax 처리 시 달라지는 부분은 컨트롤러
사진에서 오른쪽이 컨트롤러고 왼쪽은 데이터 받아야하는 ajax1.jsp다
우선 컨트롤러가 반환하는 건 디폴트 값이 jsp이기 때문에 리턴값이 jsp 이름이 아니고 데이터라는 걸 알려줘야 함. => @ResponseBody 애노테이션을 쓰면 된다 (중요) 메소드의 반환 값이 응답 데이터라는 것. ajax할때 없으면 안된다(jsp로 받아들이면 안되니까.) - 뒤에서 배우겠지만 RestController로 대체 가능하긴 하다

@RequestMapping("/ajax1")
@RequiredArgsConstructor
@Controller
public class AjaxController1 {

  private final AjaxService ajaxService;
  
  @ResponseBody  // 메소드의 반환 값이 응답 데이터이다.
  @RequestMapping(value="/list.do", method=RequestMethod.GET, produces="application/json; charset=UTF-8")  // produces : 응답 데이터 타입
  public List<AjaxDto> list() {
    return ajaxService.getDtoList();  // jackson 라이브러리가 List<AjaxDto>를 json 데이터(배열)로 자동 변환한다.
  }
  
  @ResponseBody
  @RequestMapping(value="/detail.do", method=RequestMethod.GET, produces="application/json; charset=UTF-8")
  public AjaxDto detail(@RequestParam(value="name") String name) {
    return ajaxService.getDto(name);  // jackson 라이브러리가 AjaxDto를 json 데이터(객체)로 자동 변환한다.
  }
  
}

응답데이터를 만들때는 항상 응답데이터 타입을 적어줬었다.
@RequestMapping에 produces 속성에 적어줌. produces="application/json; charset=UTF-8"
이렇게 적어주면 실제 반환 타입은 리스트지만 잭슨이 json으로 잘 받아준다

실행결과

콘솔로 잘 보내졌다.(resData)


ajax

클릭한 row의 name 전달하기 위해 ajax로 name 가져오기

ajax1.jsp fnList()

  function fnList(){
	$('#btn_list').click(function(){
      $.ajax({
    	// 요청
        type: 'get',
    	url: '${contextPath}/ajax1/list.do',
    	// 응답
    	dataType: 'json',
    	success: function(resData){
    	  $('#list').empty();
    	  $.each(resData, function(i, elem){
    	    $('#list').append('<div class="row"><span>' + elem.name + '</span>, ' + elem.age + '</div>');
    	  })
    	}
      })
	})
  }

원래는 클릭해도 이름만 전달 안됨. 그래서 elem.name 앞뒤로 span 추가해서 구분할 수 있게 해줌

ajax1.jsp fnDetail()

  function fnDetail(){
    $(document).on('click', '.row', function(){
      $.ajax({
        // 요청
        type: 'get',
        url: '${contextPath}/ajax1/detail.do',
        data: 'name=' + $(this).find('span').text(),
        // 응답
        dataType: 'json',
        success: function(resData){
          alert(resData.name + ', ' + resData.age);
        }
      })
    })
  }

클릭한 row = this(위 코드에서 append 안에 있는 div 태그 전체)
$(this).find('span')으로 하위 태그 중 span 찾아서 .text()로 내부텍스트, 즉 elem.name만 뽑아올 수 있게 해줬다.

마지막으로 컨트롤러에서 name 가져와서 출력시켜주면


클릭하면 이름만 콘솔에 출력된다

(컨트롤러에서 요청, 호출말고 딴 일하는건 좋지 않은데 여기선 임시로 했다)


7교시

한것들 좀 바꿔보기


Dto로도 똑같은거 했다. 클릭하면 하나씩 나옴. dto는 객체 형태로 전달해줌

@RestController

모든 메소드에 @ResponseBody를 추가하는 @Controller이다. (@ResponseBody 추가할 필요 없어짐)

@RequestMapping과 @GetMapping

같은 역할이지만
@RequestMapping은 클래스 레벨과 메소드 둘다 맵핑 할 수 있고
@GetMapping은 메소드에만 맵핑 할 수 있다.
그러니까 @GetMapping이 더 세분화되었다고 볼수있다.


이렇게 적으면 너무 기니까 메소드 매핑일때는 @GetMapping으로 바꿔주고 method=RequestMethod.GET 지워버리면된다. (Post일땐 PostMapping)

application/json; charset=UTF-8

스프링이 MediaType에 등록해놓음.
MediaType.APPLICATION_JSON_VALUE로 대체해서 쓸 수 있다.

  @GetMapping(value="/list.do", produces=MediaType.APPLICATION_JSON_VALUE)
  public List<AjaxDto> getDtoList() {
    return ajaxService.getDtoList();
  }

ajax는 나중에 Restful 배울 때 다시. db까지 사용해서

0개의 댓글