Внедряем данные из spring model в js-код

Written by elwood

Часто бывает нужно передать данные с серверной части на клиентскую, причём не в виде текста, а в виде готовых объектов. К сожалению, в HTML-страницу нельзя внедрить данные напрямую, но можно сгенерировать js-скрипт, в который бы передавался JSON, готовый к употреблению. Обычно я делал это вручную, но теперь решил написать спринговый interceptor, который бы перехватывал все атрибуты model, начинающиеся с “js_”, и добавлял их на клиент автоматически.

Пример использования

@RequestMapping(value = "/create", method = RequestMethod.GET)
public String viewCreate(Model model) {
	NewsArticle article = new NewsArticle();
        // Этот атрибут будет доступен только в JSP при генерации страницы
	model.addAttribute( "article", article );
	// А этот атрибут также попадёт и в js-код в качестве атрибута глобального объекта JS_DATA
	model.addAttribute( "js_article_id", article.getId() );
	return "edit";
}
$(function() {
    var articleId = JS_DATA['js_article_id'];
    // ...
});

Код

Все необходимые кусочки файлов можно посмотреть на github, а здесь приведу только код интерсептора:

public class JsDataInjectionInterceptor extends HandlerInterceptorAdapter
{
    private final static Log log = LogFactory.getLog( JsDataInjectionInterceptor.class );
 
    @Override
    public void postHandle( HttpServletRequest request,
                            HttpServletResponse response,
                            Object handler,
                            ModelAndView modelAndView ) throws Exception {
        //
        if (null == modelAndView) return;
 
        Map<String, Object> jsObjects = null;
        for ( Map.Entry<String, Object> entry : modelAndView.getModelMap().entrySet() ) {
            if (entry.getKey().startsWith( "js_" )) {
                if (null == jsObjects)
                    jsObjects = new HashMap<>(  );
                jsObjects.put( entry.getKey(), entry.getValue() );
            }
        }
        if (jsObjects != null) {
            ObjectMapper mapper = new ObjectMapper();
            mapper.enable( SerializationFeature.INDENT_OUTPUT );
            String jsData = mapper.writeValueAsString( jsObjects );
            log.debug( "JsData: " + jsData );
            modelAndView.getModelMap().addAttribute( "__js_data__",
                    jsData
            );
        }
    }
}