我在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页面,就像它应该的那样。但是当我添加图像时 - 验证不起作用,页面没有被重定向 - 但是对象被正确地存储在数据库中。
感谢您的帮助
答案 0 :(得分:1)
感谢@Gimby,我在模板文件中发现了一个小错误。 就像他在BalusC博客中发布的帖子一样,在我的模板中发布了一条能够实现无状态的行 - 这在第一时间并不是必需的。
感谢您的帮助。