Вопрос по jsf-2 – Обработка параметров просмотра в JSF после публикации

11

У меня есть несколько страниц, которым нужен userId для работы, таким образом, следующий код:

userpage.xhtml

<!-- xmlns etc. omitted -->
<html>
<f:metadata>
    <f:viewParam name="userId" value="#{userPageController.userId}"/>
</f:metadata>
<f:view contentType="text/html">
<h:head>
</h:head>
<h:body>
    <h:form>
        <h:commandButton action="#{userPageController.doAction}" value="post"/>
    </h:form>
</h:body>
</f:view>

userPageController.java

@Named
@ViewScoped
public class userPageControllerimplements Serializable {
    private static final long serialVersionUID = 1L;

    @Inject protected SessionController sessionController;
    @Inject private SecurityContext securityContext;
    @Inject protected UserDAO userDAO;

    protected User user;
    protected Long userId;

    public UserPage() {
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        if(!FacesContext.getCurrentInstance().isPostback()){
            User u = userDAO.find(userId);
            this.userId = userId;
            this.user = u;
        }
    }

    public void doAction(){

    }

}

Однако после вызова doAction параметр view в URL исчезает. Боб все еще работает из-за его видимости, но он разрушает мои попытки будущей навигации. Когда я ищу вокруг, у меня создается впечатление, что параметр представления должен оставаться после сообщения, таким образом читая userpage.jsf? UserId = 123, но это не так. Что такое на самом деле предполагаемое поведение?

В связи с этим я пытался реализовать автоматическое добавление параметров просмотра при переходе на другую страницу, где я хочу сохранить идентификатор пользователя. Кажется, это работает для других, но для меня userId в ViewRoot всегда нулевой. Приведенный ниже код использовался для получения параметра просмотра (я знаю, что мог бы использовать свой временно сохраненный userId в bean-компоненте для навигации, но это решение было бы намного интереснее):

    String name = "userId";
    FacesContext ctx = FacesContext.getCurrentInstance();
    ViewDeclarationLanguage vdl = ctx.getApplication().getViewHandler().getViewDeclarationLanguage(ctx, viewId);
    ViewMetadata viewMetadata = vdl.getViewMetadata(ctx, viewId);
    UIViewRoot viewRoot = viewMetadata.createMetadataView(ctx);
    UIComponent metadataFacet = viewRoot.getFacet(UIViewRoot.METADATA_FACET_NAME);

    // Looking for a view parameter with the specified name
    UIViewParameter viewParam = null;
    for (UIComponent child : metadataFacet.getChildren()) {
        if (child instanceof UIViewParameter) {
            UIViewParameter tempViewParam = (UIViewParameter) child;
            if (name.equals(tempViewParam.getName())) {
                viewParam = tempViewParam;
                break;
            }
        }
    }

    if (viewParam == null) {
        throw new FacesException("Unknown parameter: '" + name + "' for view: " + viewId);
    }

    // Getting the value
    String value = viewParam.getStringValue(ctx);  // This seems to ALWAYS be null.

Еще одна мысль, что методы установки все еще работают, setUserId вызывается с правильным значением в сообщении.

Я полностью не понял, как работают параметры просмотра, или здесь есть какая-то ошибка? Я думаю, что мой вариант использования должен бытьextremly общие и имеют базовую поддержку в рамках.

Ваш Ответ

2   ответа
0

<f:ajax execute="@form" render="@form" /> для работы нужно было бы также включить что-то вроде

<f:param name="userId" value="#{userPageController.userId}"/>

внутри<h:commandButton>?

Как это описано вhttps://stackoverflow.com/a/14026995/811046

25

I get the impression that the view parameter should remain after a post thus reading userpage.jsf?userId=123, but this is not the case. What is really the intended behaviour?

Это поведение правильно.<h:form> генерирует HTML<form> элемент с URL действияwithout любые параметры просмотра. Запрос POST просто отправляет именно этот URL. Если вы намереваетесь сохранить параметры просмотра в URL-адресе, то есть три основных способа:

Bring in some ajax magic.

<h:commandButton action="#{userPageController.doAction}" value="post">
    <f:ajax execute="@form" render="@form" />
</h:commandButton>

This way the initially requested page and thus also the request URL in browser's address bar remains the same all the time.

If applicable (e.g. for page-to-page navigation), make it a GET request and use includeViewParams=true. You can use <h:link> and <h:button> for this:

<h:button outcome="nextview?includeViewParams=true" value="post" />

However, this has an EL security exploit in Mojarra versions older than 2.1.6. Make sure that you're using Mojarra 2.1.6 or newer. See also issue 2247.

Control the generation of action URL of <h:form> yourself. Provide a custom ViewHandler (just extend ViewHandlerWrapper) wherein you do the job in getActionURL().

public String getActionURL(FacesContext context, String viewId) {
    String originalActionURL = super.getActionURL(context, viewId);
    String newActionURL = includeViewParamsIfNecessary(context, originalActionURL);
    return newActionURL;
}

To get it to run, register it in faces-config.xml as follows:

<application>
    <view-handler>com.example.YourCustomViewHandler</view-handler>
</application>

This is also what OmniFaces <o:form> is doing. It supports an additional includeViewParams attribute which includes all view parameters in the form's action URL:

<o:form includeViewParams="true">

Update: получение параметров представления текущего представления программно (что в основном является вашим вторым вопросом) должно быть сделано следующим образом:

Collection<UIViewParameter> viewParams = ViewMetadata.getViewParameters(FacesContext.getCurrentInstance().getViewRoot());

for (UIViewParameter viewParam : viewParams) {
    String name = viewParam.getName();
    Object value = viewParam.getValue();
    // ...
}
Работает как шарм, я должен был изучить код, который я включил ближе, и заметил & quot; createViewMetadata & quot; ... Отличный ответ, как всегда! Rasmus Franke
Думаю, третий - это хорошо известные варианты.
Добро пожаловать :)
Это потому, что вы создаете совершенно новый вид, а не используете текущий вид. Смотрите обновленный ответ.
Я, вероятно, буду использовать 1. для решения проблемы с адресной строкой. О 2: это было бы чистым решением для просмотра обработки параметров, но оно работает только при использовании одного и того же управляемого компонента на 2 страницах (что я обычно считаю плохим выбором), что делает его бесполезным. Я, скорее всего, в итоге просто определю параметры вручную в каждой ссылке. У вас есть какие-либо идеи о том, что код внизу не работает? Получение параметра просмотра программно, то есть. Rasmus Franke

Похожие вопросы