Как обработать ответ ajax на страницу jsf, используя springmvc в качестве контроллера - PullRequest
0 голосов
/ 04 марта 2011

Я работаю над проектом, который использует Spring-MVC в качестве контроллера, а JSF отвечает за рендеринг. Теперь мне нужно реализовать некоторые функции Ajax на моей странице. Я ищу что-то вроде этого:

  1. Пользователь нажимает кнопку или «что-то другое», нажимаемое
  2. Ajax-вызов выполняется для контроллера, и до тех пор, пока не будет получен ответ, под кнопкой
  3. Контроллер обработает запрос и вернет результат в виде HTML. Результат будет отображен на панели аналогичной информации «loading ...».

Шаг 3, когда я потерялся. Пока что я обнаружил, что для достижения такой функциональности «из коробки» мне нужно использовать простые JSP и тайлы ( Обработка запросов Ajax с помощью контроллеров Spring MVC ). Но мне нужно использовать JSF и один из моих фрагментов XHTML в качестве «шаблона».
У меня уже есть преобразователь AJAX, настроенный в моем файле конфигурации Spring, но он используется для возврата объектов JSON. Теперь мне нужно вернуть весь HTML. Я хочу использовать сервер для рендеринга, а не макетировать его из объекта JSON и вставить HTML-код в нужное место на странице. Есть ли способ, как «убедить» org.springframework.faces.mvc.JsfView работать в AJAX-запросе? Это моя обычная конфигурация распознавателя JSF:

<bean id="jsfViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.faces.mvc.JsfView" />   
    <property name="prefix" value="/WEB-INF/pages/" />
    <property name="suffix" value=".xhtml" />
</bean>

А это моя конфигурация распознавателя JSON Ajax:

<bean id="ajaxViewResolver" class="com.myproject.web.springmvc.AjaxViewResolver">
    <property name="ajaxView">
        <bean class="com.myproject.web.springmvc.AjaxView" />
    </property>
    <property name="ajaxPrefix" value="ajax_"></property>
</bean>

Вот код в моем JSON AjaxViewResolver:

public class AjaxViewResolver extends AbstractCachingViewResolver {

private Logger logger = Logger.getLogger(AjaxViewResolver.class);

private String ajaxPrefix;

private View ajaxView;

@Override
protected View loadView(String viewName, Locale locale) throws Exception {
    logger.debug("loadView - enter");
    logger.debug("loadView - viewName : " + viewName);
    logger.debug("loadView - locale : " + locale);

    View view = null;
    if (viewName.startsWith(this.ajaxPrefix)) {
        view = ajaxView;
    }

    logger.debug("loadView - returns : " + view);
    return view;
}

public String getAjaxPrefix() {
    return ajaxPrefix;
}

public void setAjaxPrefix(String ajaxPrefix) {
    this.ajaxPrefix = ajaxPrefix;
}

public View getAjaxView() {
    return ajaxView;
}

public void setAjaxView(View ajaxView) {
    this.ajaxView = ajaxView;
}

}

Вот мой класс JSON AjaxView:

public class AjaxView extends AbstractView {
private Logger logger = Logger.getLogger(AjaxView.class);

/**
 * Serialises the modelMap into a JSON string and writes the string to the outputStream
 */
@Override
protected void renderMergedOutputModel(Map map, HttpServletRequest request, HttpServletResponse response) throws Exception {
    logger.debug("renderMergedOutputModel - enter");
    logger.debug("renderMergedOutputModel - map : " + map);
    logger.debug("renderMergedOutputModel - request : " + request);
    logger.debug("renderMergedOutputModel - response : " + response);

    JSONSerializer serializer = new JSONSerializer();
    serializer.exclude("*.class");
    String jsonString = serializer.deepSerialize(map);
    response.setContentType("text/plain; charset=UTF-8");
    response.getOutputStream().write(jsonString.getBytes());

    logger.debug("renderMergedOutputModel - response : " + response);
    logger.debug("renderMergedOutputModel - exit");
}

}

Есть идеи?

1 Ответ

1 голос
/ 04 марта 2011

Похоже, никто никогда не нуждался в этом. Я провел последние пару часов, просматривая код JSF и Spring MVC, и пришел с одним решением, которое работает для меня. Я хотел бы представить это здесь, и если вы, ребята, можете сделать некоторую экспертную оценку. Спасибо.

Решение состоит в том, чтобы создать новый bean-компонент на основе com.myproject.web.springmvc.AjaxViewResolver и в свойство ajaxView добавить недавно созданный класс nz.co.bnz.olb.ib.web.springmvc.AjaxJsfView, который расширяет org.springframework.faces.mvc.JsfView.
Вот пример конфигурации Spring:

<bean id="ajaxJsfViewResolver" class="nz.co.bnz.olb.ib.web.springmvc.AjaxViewResolver">
    <property name="ajaxView">
        <bean class="nz.co.bnz.olb.ib.web.springmvc.AjaxJsfView">
            <property name="prefix" value="/WEB-INF/pages/" />
            <property name="suffix" value=".xhtml" />
        </bean>
    </property>
    <property name="ajaxPrefix" value="ajaxJsf_"></property>
</bean>

Как видите, мне пришлось передать атрибут prefix и suffix, чтобы определить, как будет формироваться URL для моих файлов XHTML (необходимо для JsfView). Я также создал новый префикс ajaxJsf_ для этого преобразователя. Вот новый класс:

public class AjaxJsfView extends JsfView {
private Logger logger = Logger.getLogger(AjaxJsfView.class);

private String prefix;

private String suffix;

private String viewName;

@Override
protected void renderMergedOutputModel(Map map, HttpServletRequest request, HttpServletResponse response) throws Exception {
    logger.debug("renderMergedOutputModel - enter");
    logger.debug("renderMergedOutputModel - map : " + map);
    logger.debug("renderMergedOutputModel - request : " + request);
    logger.debug("renderMergedOutputModel - response : " + response);

    viewName = (String)map.get("view");

    super.renderMergedOutputModel(map, request, response);

    logger.debug("renderMergedOutputModel - response : " + response);
    logger.debug("renderMergedOutputModel - exit");
}

public String getPrefix() {
    return prefix;
}

public void setPrefix(String prefix) {
    this.prefix = prefix;
}

public String getSuffix() {
    return suffix;
}

public void setSuffix(String suffix) {
    this.suffix = suffix;
}

@Override
public String getUrl() {
    return getPrefix() + viewName + getSuffix();
}

@Override
public void setUrl(String arg0) {
    super.setUrl(arg0);
}
}

Определение фактического файла, используемого в качестве «представления», можно увидеть в методе renderMergedOutputModel. Он взят из нашей «модели» с карты под ключом «просмотр». Полный путь к «представлению» реализован в переопределенном методе getUrl(). Поэтому в качестве последнего шага мне пришлось реализовать метод моего контроллера для возврата карты с ожидаемым значением в ней:

public ModelAndView getSomeTest(HttpServletRequest request, HttpServletResponse response){
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("view", "pathToMyXHTMLFile/someTest");
    map.put("name", "tomik");

    ModelAndView returnModelAndView = new ModelAndView("ajaxJsf_increaseLimit", map);

    return returnModelAndView;
}

И, наконец, это XHTML, используемый и в конечном итоге возвращаемый в виде HTML с заполненными значениями:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jstl/core">

    <p>Hello <h:outputText value="#{name}"/></p>
</ui:composition>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...