无状态视图不支持@ViewScoped bean

时间:2015-08-11 10:27:47

标签: jsf jsf-2.2 view-scope

我在JSF中有一个页面:

    <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:f="http://xmlns.jcp.org/jsf/core">

    <ui:param name="navLinkActive" value="poiAdder"/>

    <ui:define name="content">

        <h:outputStylesheet library="clock" name="clockpicker.css"/>
        <h:outputScript library="clock" name="clockpicker.js"/>
        <script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>

        <div class="col-md-12">

            <ui:include src="/WEB-INF/lego/leftMenu.xhtml"/>

            <div class="col-md-10">

                <h:form id="poiForm" prependId="false" enctype="multipart/form-data">

                    <div class="col-md-6">

                        <h:outputLabel for="address"
                                       value="Adres"/>
                        <h:inputText id="address"
                                     styleClass="col-md-10"
                                     value="#{poiAdderBean.poi.address}"
                                     requiredMessage="#{msg.fieldRequired}"
                                     required="true"/>
                        <input type="button"
                               class="btn btn-default"
                               value="#{msg.findAddress}"
                               onclick="codeAddress()"/>
                        <h:message for="address" style="display: block; color:red"/>

                        <h:outputLabel for="longitude"
                                       value="Współrzędne (automatycznie)"/>
                        <h:outputLabel for="latitude"
                                       styleClass="descriptionLabel"
                                       value="podaj adres, a potem wybierz dokładną lokalizację na mapie, jeśli potrzebne"/>

                        <div class="col-md-12">
                            <h:inputText id="longitude"
                                         styleClass="col-md-4 col-md-offset-2"
                                         required="true"
                                         requiredMessage="#{msg.fieldRequired}"
                                         value="#{poiAdderBean.poi.longitude}"
                                         converter="javax.faces.Double">
                            </h:inputText>

                            <h:inputText id="latitude"
                                         styleClass="col-md-4"
                                         required="true"
                                         requiredMessage="#{msg.fieldRequired}"
                                         value="#{poiAdderBean.poi.latitude}"
                                         converter="javax.faces.Double">
                            </h:inputText>
                        </div>
                        <h:message for="latitude" style="display: block; color:red"/>
                        <h:message for="longitude" style="display: block; color:red"/>

                        <h:outputLabel for="poiTypeSelector"
                                       value="Wybierz kategorię POI"/>
                        <h:selectOneMenu id="poiTypeSelector"
                                         styleClass="btn"
                                         value="#{poiAdderBean.poi.poiCategory}">
                            <f:selectItems value="#{poiAdderBean.poiCategoryList}"
                                           var="poiCat"
                                           itemLabel="#{msg['poi'.concat(poiCat)]}"
                                           itemValue="#{poiCat}"/>
                        </h:selectOneMenu>

                        <h:outputLabel for="phoneNumber"
                                       value="#{msg.phoneNumber}"/>
                        <h:inputText id="phoneNumber"
                                     style="width: 350px"
                                     value="#{poiAdderBean.poi.phone}"
                                     validator="#{PhoneValidator.validate}">
                        </h:inputText>
                        <h:message for="phoneNumber" style="display: block; color:red"/>

                        <h:outputLabel for="linkwww1"
                                       value="Link www #1"/>
                        <h:inputText id="linkwww1"
                                     style="width: 350px"
                                     value="#{poiAdderBean.poi.link}">
                            <f:validator validatorId="linkValidator"/>
                            <f:attribute name="linkDescritpion" value="#{description1}"/>
                        </h:inputText>
                        <h:message for="linkwww1" style="display: block; color:red"/>

                        <h:outputLabel for="linkwww1Description"
                                       value="Opis #1"/>
                        <h:inputText id="linkwww1Description"
                                     binding="#{description1}"
                                     style="width: 350px"
                                     value="#{poiAdderBean.poi.linkDescription}">
                        </h:inputText>
                        <h:message for="linkwww1Description" style="display: block; color:red"/>

                        <h:outputLabel for="linkwww2"
                                       value="Link www #2"/>
                        <h:inputText id="linkwww2"
                                     style="width: 350px"
                                     value="#{poiAdderBean.poi.link2}">
                            <f:validator validatorId="linkValidator"/>
                            <f:attribute name="linkDescritpion" value="#{description2}"/>
                        </h:inputText>
                        <h:message for="linkwww2" style="display: block; color:red"/>

                        <h:outputLabel for="linkwww2Description"
                                       value="Opis #2"/>
                        <h:inputText id="linkwww2Description"
                                     binding="#{description2}"
                                     style="width: 350px"
                                     value="#{poiAdderBean.poi.link2Description}">
                        </h:inputText>
                        <h:message for="linkwww2Description" style="display: block; color:red"/>

                        <h:outputLabel value="#{msg.openingHours}"/>

                        <div class="col-md-12">
                            <div class="col-md-6">
                                <div class="input-group clockpicker">
                                    <span class="input-group-addon" id="from">DO</span>
                                    <h:inputText styleClass="form-control"
                                                 id="clockInputStart"
                                                 value="#{poiAdderBean.poi.openHoursStart}">
                                    </h:inputText>
                                    <span class="input-group-addon" id="timeFrom">
                                        <span class="glyphicon glyphicon-time"></span>
                                    </span>
                                </div>
                            </div>
                            <div class="col-md-6">
                                <div class="input-group clockpicker">
                                    <span class="input-group-addon" id="to">DO</span>
                                    <h:inputText styleClass="form-control"
                                                 id="clockInputStop"
                                                 value="#{poiAdderBean.poi.openHoursStop}">
                                    </h:inputText>
                                    <span class="input-group-addon" id="timeTo">
                                        <span class="glyphicon glyphicon-time"></span>
                                    </span>
                                </div>
                            </div>
                        </div>

                        <div class="col-md-12">
                            <h:outputLabel for="disableAccess"
                                           value="#{msg.disableAccess}"/>
                            <h:selectBooleanCheckbox id="disableAccess"
                                                     value="#{poiAdderBean.poi.disableAccess}">
                            </h:selectBooleanCheckbox>
                        </div>

                        <div class="col-md-6">
                            <h:outputLabel for="titlePl" value="#{msg.polishTitle}"/>
                            <h:inputText id="titlePl"
                                         value="#{poiAdderBean.polish.title}"
                                         required="true"
                                         requiredMessage="#{msg.fieldRequired}"/>
                            <h:message for="titlePl" style="display: block; color:red"/>

                        </div>

                        <div class="col-md-6">
                            <h:outputLabel for="titleEng" value="#{msg.englishTitle}"/>
                            <h:inputText id="titleEng"
                                         value="#{poiAdderBean.english.title}"
                                         required="true"
                                         requiredMessage="#{msg.fieldRequired}"/>
                            <h:message for="titleEng" style="display: block; color:red"/>

                        </div>

                        <div class="col-md-6">
                            <h:outputLabel for="descriptionPl" value="#{msg.descriptionPl}"/>
                            <h:inputTextarea id="descriptionPl"
                                             value="#{poiAdderBean.polish.description}"
                                             style="resize: none"
                                             required="true"
                                             styleClass="form-control"
                                             rows="4"
                                             requiredMessage="#{msg.fieldRequired}"/>
                            <h:message for="descriptionPl" style="display: block; color:red"/>

                        </div>

                        <div class="col-md-6">
                            <h:outputLabel for="descriptionEng" value="#{msg.descriptionEn}"/>
                            <h:inputTextarea id="descriptionEng"
                                             value="#{poiAdderBean.english.description}"
                                             required="true"
                                             style="resize: none"
                                             styleClass="form-control"
                                             rows="4"
                                             requiredMessage="#{msg.description}"/>
                            <h:message for="descriptionEng" style="display: block; color:red"/>
                        </div>
                        <div class="col-md-6">
                            <h:inputFile styleClass="btn btn-default" id="file" value="#{poiAdderBean.uploadedFile}">
                                <f:ajax listener="#{poiAdderBean.uploadFile()}" execute="@this"/>
                            </h:inputFile>
                        </div>
                    </div>

                    <div class="col-md-6">
                        <div id="map-canvas" style="height: 600px;"></div>
                    </div>

                    <div class="col-md-12 loginSubmit">
                        <h:commandButton styleClass="btnDefault"
                                         style="margin-top: 50px"
                                         value="#{msg.add}"
                                         action="#{poiAdderBean.createPoi}">
                        </h:commandButton>
                    </div>
                </h:form>
            </div>
        </div>

        <script type="text/javascript">
            // <![CDATA[

            $('.clockpicker').clockpicker({
                placement: 'bottom',
                align: 'left',
                autoclose: true,
                'default': 'now'
            });

            var map;
            var marker;
            var geocoder;
            google.maps.event.addDomListener(window, 'load', initialize);


            function initialize() {

                geocoder = new google.maps.Geocoder();

                var mapOptions = {
                    zoom: 13,
                    center: new google.maps.LatLng(50.05923273190915, 19.92233544588089)
                };

                map = new google.maps.Map(document.getElementById('map-canvas'),
                        mapOptions);

                google.maps.event.addListener(map, 'click', function (event) {
                    setLatLong(event.latLng);
                    makeMarker(map, event.latLng);
                    codeLatLng(event.latLng);
                }); //end addListener

            }

            function makeMarker(map, latLong) {
                if (marker != null) {
                    marker.setMap(null);
                }
                marker = new google.maps.Marker({
                    position: latLong,
                    map: map
                });
            }

            function codeAddress() {
                var address = document.getElementById("address").value;
                if (address != null && address != "") {
                    geocoder.geocode({'address': address}, function (results, status) {
                        if (status == google.maps.GeocoderStatus.OK) {
                            var location = results[0].geometry.location;
                            map.setCenter(location);
                            map.setZoom(18);
                            makeMarker(map, location);
                            setLatLong(location);
                        }
                        else {
                            alert("Geocode was not successful for the following reason: " + status);
                        }
                    });
                } else {
                    alert("Nie podano adresu");
                }
            }

            function codeLatLng(latLng) {
                geocoder.geocode({
                    'latLng': latLng
                }, function (results, status) {
                    if (status === google.maps.GeocoderStatus.OK) {
                        if (results[0]) {
                            document.getElementById("address").value = results[0].formatted_address;
                            console.log(results[0]);
                        } else {
                            alert('No results found');
                        }
                    } else {
                        alert('Geocoder failed due to: ' + status);
                    }
                });
            }

            function setLatLong(location) {
                document.getElementById("longitude").value = location.lng();
                document.getElementById("latitude").value = location.lat();
            }
            //]]>
        </script>

    </ui:define>

</ui:composition>

和此页面的bean:

import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.event.Event;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.Part;
import java.io.*;

@Named("poiAdderBean")
@SessionScoped
public class PoiAdderBean implements Serializable {

    @Inject
    PrincipalBean principalBean;

    @Inject
    @Created
    Event<Poi> poiCreated;

    private Poi poi;
    private Translation polish;
    private Translation english;
    private Part uploadedFile;
    private Image image;

    public void uploadFile() {
        image = new Image();
        byte[] bytes = new byte[0];
        if (uploadedFile!= null) {
            try {
                InputStream is = uploadedFile.getInputStream();
                if (is != null) {
                    bytes = IOUtils.toByteArray(is);
                    is.close();
                }
            } catch (IOException e) {
                FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                        "error uploading file",
                        null);
                FacesContext.getCurrentInstance().addMessage(null, msg);
            }
        }
        image.setContent(bytes);
        image.setContentType(uploadedFile.getContentType());
    }

    public Part getUploadedFile() {
        return uploadedFile;
    }

    public void setUploadedFile(Part uploadedFile) {
        this.uploadedFile = uploadedFile;
    }

    public Poi getPoi() {
        return poi;
    }

    public void setPoi(Poi poi) {
        this.poi = poi;
    }

    public Translation getPolish() {
        return polish;
    }

    public void setPolish(Translation polish) {
        this.polish = polish;
    }

    public Translation getEnglish() {
        return english;
    }

    public void setEnglish(Translation english) {
        this.english = english;
    }

    public PoiCategory[] getPoiCategoryList(){
        return PoiCategory.values();
    }

    @PostConstruct
    public void init(){
        poi = new Poi();
        polish = new Translation(Language.PL, Status.READY);
        english = new Translation(Language.EN, Status.READY);
    }

    public String createPoi(){
        english.setAuthor(principalBean.getLoggedUser());
        polish.setAuthor(principalBean.getLoggedUser());

        poi.addTranslation(polish);
        poi.addTranslation(english);

        polish.setPoi(poi);
        english.setPoi(poi);

        if(image != null){
            poi.setImage(principalBean.getDataAccess().mergeEntity(image));
        }

        principalBean.getDataAccess().mergeEntity(poi);

        poiCreated.fire(poi);

        return "/secure/poiTranslator.xhtml?faces-redirect=true";
    }
}

对于一些完全奇怪且不为人知的原因,页面底部始终显示错误消息:

  

无状态视图不支持@ViewScoped bean

但这显然是@SessionScoped bean。我无法找到此错误的来源,这就是我发布完整代码的原因。

PLUS - 当我没有上传文件时 - 验证工作正常,并且在数据库中成功编写Poi对象后,页面被重定向到poiTranslator页面,就像它应该的那样。但是当我添加图像时 - 验证不起作用,页面没有被重定向 - 但是对象被正确地存储在数据库中。

感谢您的帮助

1 个答案:

答案 0 :(得分:1)

感谢@Gimby,我在模板文件中发现了一个小错误。 就像他在BalusC博客中发布的帖子一样,在我的模板中发布了一条能够实现无状态的行 - 这在第一时间并不是必需的。

感谢您的帮助。

link to BalusC artickle