Spring MVC 에서 하나의 Request 요청이 올때 보통 비지니스 로직을 거쳐, 가공된 데이터는 jsp 나 freemarker 같은 view단으로 보내지게 됩니다.
하지만 기존웹 & 모바일웹과 네이티브 모바일앱에 모두 대처하기 위해서는 단일 Request에서 해당 데이터를 jsp와 같은 view단을 위한 request mapping 뿐만 아니라, 모바일 Client을 위한 json , 크로스 도메인에 대처하기 위한 jsonp 까지 제공할려면 어떻게 해야 할까요.
예를 들어,
http://localhost/member/profile - 전통적인 view를 보여줍니다.
http://localhost/member/profile.json - json형태를 반화
http://localhost/member/profile.jsonp - jsonp 형태를 변환
ContentNegotiatingViewResolver
ContentNegotiatingViewResolver 를 이용하면, 위와 같이 하나의 URI에 *.json 등과같이 mediaType 에 변화를 줌으로써 해당 형태의 페이지를 각각 제공 해 줄 수 있습니다.
ContentNegotiatingViewResolver 의 사용 방법은 아래와 같습니다.
<bean class=" org.springframework.web.servlet.view.contentnegotiatingviewresolver">
<!-- ViewResolver 우선순위 설정 -->
<property name="order" value="1" />
<property name="mediaTypes">
<!-- 맵핑될 확장자 정의 -->
<map>
<entry key="json" value="application/json" />
<entry key="jsonp" value="javascript/jsonp" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- JSON 요청을 처리할 뷰 -->
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
<!-- JSONP 요청을 처리할 뷰 -->
<bean class="com.jce.commons.controller.JSONPView">
<property name="contentType" value="javascript/jsonp"/>
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
< /bean>
- 기존의 FreeMarkerViewResolver 위에 위와 같이 ContentNegotiatingViewResolver를 정의합니다.
mediaTypes의 entry의 key에 json, jsonp 등과 같이 원하는 형식의 mediaType 을 설정하고,
entry에 view에는 json이라면 application/json과 같이 contentType을 설정합니다.
- 설정된 mediaType 정보를 바탕으로 아래쪽 defaultViews 목록에 정의된 view들 중에서 랜더링 가능한 view를 찾게 됩니다. 그 기준은 defaultView의 list에 정의된 view class의 contentType 입니다.
- list 의 JSONPView 같은 경우는 jsonp를 위해 정의한 클래스인데, 이와 같이 필요해 따라 개발자가 AbstractView를 상속받아 직접 구현 할 수 도 있습니다.
JSONPView
public class JSONPView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String callback = request.getParameter("callback")!=null?request.getParameter("callback"):"?";
ObjectMapper om = new ObjectMapper();
String json = om.writeValueAsString(model);
response.setContentType("javascript/jsonp");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(callback+"("+json+");");
}
}
Controller
@Controller
@RequestMapping("/member")
public class MemberContoller extends BaseController {
@RequestMapping(value="/profile", method=RequestMethod.GET)
public void profile(Model model) throws Exception {
List<Map<String,Object>> dataList = new ArrayList<Map<String, Object>>();
Map<String, Object> data = new HashMap<String,Object>();
data.put("name","정민혁");
data.put("lv:",10);
dataList.add(data);
data = new HashMap<String,Object>();
data.put("name","잡스");
data.put("lv",99);
dataList.add(data);
model.addAttribute("personList", dataList);
}
}
실제로 테스트 해보겠습니다.
default
출처 : http://stunstun.tistory.com/37