Spring - 비동기(Ajax) 통신하기

2019. 10. 31. 18:19Java/Basic

반응형

뷰 화면에서 Ajax와 같은 비동기 요청을 보냈을 경우, 페이지 이동없이 ResponseBody만 응답해야 합니다.

페이지 이동 없이 Json 데이터만 전송하는 방법은 크게 2가지가 있습니다.

  1. @ResponseBody로 ajax 데이터 내보내기
  2. MappingJackson2JsonView bean으로 ajax 데이터 내보내기
    • Model에 response를 담고 viewName에 MappingJackson2JsonView 빈 이름 설정
    • ModelAndView에 response와 viewName 설정

먼저, 컨트롤러 메서드를 작성하기 전에 ajax 함수를 살펴봅시다.

var fn_ajax_data = function(type, url, formData){
  $("body > div").append('<div id="data-loading" class="spinner-border text-muted">')
  $.ajax({
    type : type,
    dataType : 'json',
    contentType : "application/json",
    data : JSON.stringify(formData),
    url : url,
    beforeSend : function(xhr){
      xhr.setRequestHeader($("meta[name='_csrf_header']").attr("content"), $("meta[name='_csrf']").attr("content"));
    },
    success : function(res) {
      $("#data-loading").remove();
      if (res.success == true) {
        $('.notifyjs-corner').empty();
        $.notify((type == "put" ? "수정" : type == "delete" ? "삭제 " : "등록") + " 완료되었습니다.");
        if (typeof res.nextPage !== "undefined") {
          setTimeout(function() {
          window.location = COMMON.ctx + res.nextPage
          }, 500);
        } else {
          setTimeout(function() {
            window.location = (type == "put" ? document.referrer
            : url.slice(0, url.lastIndexOf("/")))}, 800);
        }
      } else {
        $("#data-loading").hide();
        $('.notifyjs-corner').empty();
        $.notify("crud fail");
      }
    },
    error : function(error) {
      alert(error.errorMsg);
    }
  });
};

fn_ajax_data 함수는 jQuery로 작성된 함수로 http method type, url, form데이터를 객체화한 값을 인자로 받습니다.
csrf security가 enabled 상태라면 csrf 헤더를 포함시키지 않을시 403 에러가 발생되므로, 메서드 전송 전에 header에 csrf 관련 헤더를 포함시킵니다.
(csrf.disabled() 상태라면 추가하지 않아도 됩니다.)

정상적으로 전송했을 시 실행되는 일련의 과정은 필요에 따라 custom 하면 됩니다.


1. @ResponseBody로 ajax 데이터 내보내기

@RequestMapping("/v/users")
@Controller
public class VUserController {

	private final static String currentPage = "user";
	private final UserService userService;

	@Autowired
	public VUserController(UserService userService) {
		this.userService = userService;
	}

	@PutMapping(value = "/{id}")
	public @ResponseBody Map<String, Object> modifyUser(@PathVariable("id") User oriUser,
				@RequestBody Map<String, String> userValue) {
		Map<String, Object> mv = new HashMap<>();
		mv.put("success", userService.modify(oriUser, userValue) > 0 ? true : false);		
		mv.put("currentPage", currentPage);
		return mv;
	}
}

@ReponseBody 애너테이션을 이용하면, 페이지 이동 없이 리소스만 전송시킬 수 있다.


2. MappingJackson2JsonView bean으로 ajax 데이터 내보내기

만일, 웹 뷰 관련 컨트롤러 내에 정의한 페이지 이동있는 다른 메서드와 형태를 동일시 하고 싶다면, MappingJackson2JsonView 빈을 이용하면 된다.

spring boot를 이용중이고, spring-boot-starter-web 스타터 폼 의존성 라이브러리 내에 정의된 클래스이기 때문에 이미 web 스타터 폼을 사용하고 있다면, dependency 추가할 필요가 없습니다.

만일 spring-boot-starter-web 스타터 폼을 이용하고 있지 않다면 아래의 라이브러리를 pom.xml에 추가하면 됩니다.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

1) Model에 response를 담고 viewName에 MappingJackson2JsonView 빈 이름 설정

@Configuration
public class WebConfig implements WebMvcConfigurer {

	...

	@Bean
	public MappingJackson2JsonView jsonView() {
		return new MappingJackson2JsonView();
	}
}

JavaConfig 에 MappingJackson2JsonView 빈을 생성한다.
빈 이름을 따로 정의하지 않을 경우, 메서드 명이 빈 이름이 되기 때문에, 나중에 viewName 지정할 때 "jsonView" 를 입력하면 됩니다.


@PutMapping(value = "/{id}")
public String modifyUser(Model model, @PathVariable("id") User oriUser,
			@RequestBody Map<String, String> userValue) {
	model.addAttribute("success", userService.modify(oriUser, userValue) > 0 ? true : false);		
	model.addAttribute("currentPage", currentPage);
	return "jsonView";
}

ln 6과 같이 jsonView로 정의하면 json data를 client로 바로 보낼 수 있다.


2) ModelAndView에 response와 viewName 설정

Model + viewName = ModelAndView
1)번 째에서는 model을 인자로 받아 전송할 데이터를 addAttribute로 추가하고, jsonView페이지를 리턴했다면
여기서는 ModelAndView를 인자로 받아, 그 인자에 "jsonView" 페이지를 viewName 설정하고, addObject로 전송할 데이터를 추가합니다.

@PutMapping(value = "/{id}")
public ModelAndView modifyUser(ModelAndView mv, @PathVariable("id") User oriUser,
			@RequestBody Map<String, String> userValue) {
	mv.setViewName("jsonView");
	mv.addObject("success", userService.modify(oriUser, userValue) > 0 ? true : false);		
	mv.addObject("currentPage", currentPage);
	return mv;
}
``
728x90
반응형