İçerikler :

Bir String Listesi için Converter Örneği convertDateTime ile Tarih Biçimlendirme Flash Scope Google Map Marker Kullanılarak JSF de Konum B.. Java Server Faces - JSF JSF'de Yorum JSF 2.3 ve Tomcat 9 ile Web Projesi Yaratmak JSF Framework Matrix JSF Sürümlerinin Çıkış Tarihi ve Spesifikasyo.. Mamaged Bean'den Resource Bilgilerine Erişime.. No Head Component Has Been Defined Hatası Omnifaces Project Stage Tanımlama ve Olabilecek Değerle.. Repeat Döngüsünde Index Değerini Öğrenmek ResourceHandlerWrapper Kullanarak Resource Ba.. selectBooleanCheckbox ile valueChangeListener.. SelectOneMenu ile Enum Kullanılan Bir Örnek Tomcat 10 ile JSF 3.0 ile Web Projesi Tomcat 9 ve JSF 2.3 ile Bir Web Socket Örneği ViewHandlerWrapper Kullanarak Form Action De.. Web Tarayıcısında Clipboard'a JSON Verisini K..

Bu Sayfayı Paylaş:

Kavram

Java Server Faces - JSF

Tanım: Java'da web projeleri için kullanılan, bileşen tabanlı , olay yönelimli (event driven) ve MVC modeline uygun geliştirilen framework

Veri

JSF Sürümlerinin Çıkış Tarihi ve Spesifikasyon Dosyaları

Java Server Faces (JSF) sürümleri, yayınlanma yılları ve spesifikasyonları aşağıdaki gibidir :

Kaynak

JSF Framework Matrix

JSF temelli framework'lerin destek durumlarını bir tablo şeklinde gösteren site

Kavram

Omnifaces

Tanım: JSF ile ilgili yardımcı araçlar (utility) ve bileşenler sağlayan bir kütüphane

Örnek

Google Map Marker Kullanılarak JSF de Konum Bilgisinin Alınması

Aşağıdaki örnekte kullanıcıya google map gösteriyoruz. Kullanıcı marker'ı sürükleyerek istedediği bir konumu seçmesini sağlıyoruz :

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> 
<h:head> 
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> 
<script type="text/javascript"> 
var geocoder = new google.maps.Geocoder(); 
function updateMarkerPosition(latLng) { 
	  document.getElementById('testform:info').innerHTML = [ 
	    latLng.lat(), 
	    latLng.lng() 
	  ].join(', '); 
	  document.getElementById('testform:infoLatitude').value = latLng.lat(); 
	  document.getElementById('testform:infoLongitude').value = latLng.lng(); 
	} 
function initialize() { 
	  var latLng = new google.maps.LatLng(41.00554818815703, 29.036333984374778); 
	  var map = new google.maps.Map(document.getElementById('mapCanvas'), { 
	    zoom: 8, 
	    center: latLng, 
	    mapTypeId: google.maps.MapTypeId.ROADMAP 
	  }); 
	  var marker = new google.maps.Marker({ 
	    position: latLng, 
	    title: 'Point A', 
	    map: map, 
	    draggable: true 
	  }); 
	  google.maps.event.addListener(marker, 'dragend', function() { 
		  updateMarkerPosition(marker.getPosition()); 
	  }); 
} 
google.maps.event.addDomListener(window, 'load', initialize); 
</script> 
<style> 
  #mapCanvas { 
    width: 400px; 
    height: 400px; 
  } 
</style> 
</h:head> 
<body>  
<h:form id="testform"> 
	<div id="mapCanvas"></div> 
	  
	<h:outputText id="info" value="Koordinarlar Buraya Yazılacak" /> 
	<h:inputHidden value="#{testBean2.latitude}" id="infoLatitude"/> 
	<h:inputHidden value="#{testBean2.longitude}" id="infoLongitude"/>	  
	  
	<h:commandButton action="#{testBean2.submit}" value="Ok" />	 
</h:form> 
</body> 
</html> 


Java Bean kısmı ise sadece latitude ve longitude şeklinde iki özelliği vardır ve submit edildiğinde bu değerleri ekrana basmaktadır :

 

@ManagedBean 
@SessionScoped 
public class TestBean2 { 
	String latitude; 
	String longitude; 
	public String getLatitude() { 
		return latitude; 
	} 
	public void setLatitude(String latitude) { 
		this.latitude = latitude; 
	} 
	public String getLongitude() { 
		return longitude; 
	} 
	public void setLongitude(String longitude) { 
		this.longitude = longitude; 
	}	 
	public String submit(){		 
		System.out.println("latitude:"+latitude); 
		System.out.println("longitude:"+longitude);		 
		return "";		 
	}	 
} 


Google map varsayılan olarak İstanbul ile açılacaktır. Marker drag işlemi tamamlandığında updateMarkerPosition fonksiyonu çağrılacak ve infoLatitude ve infoLongitude hidded form değerleri set edilir.


İpucu

No Head Component Has Been Defined Hatası

JSF'de "One or more resources have the target of 'head', but no 'head' component has been defined within the view" gibi bir hata alırsanız view içinde head etiketini h:head olarak değiştirmeniz gerekir. 


İpucu

selectBooleanCheckbox ile valueChangeListener Kullanımı

Bir onay kutusuna tıklandığında sunucuya gidilmesi isteniyorsa aşağıdaki gibi yapılmalıdır : 

<h:selectbooleancheckbox id=“approveId" value="#{XBean.xvalue}"  onclick="submit();" immediate="true" 
valueChangeListener="#{XBean.xValueChangeListener}"/>

Görüldüğü gibi click'leme işleminde form sunucuya gönderilmektedir. Validasyon'a takılmaması içinde immediate özelliği true yapılmıştır. 

Sunuc tarafındaki xValueChangeListener fonksiyonu aşağıdaki gibidir : 

public void checkedClicked(ValueChangeEvent event) {
// kod
}

Not : valueChangeListener ajax özelliği sergilemez. Yani suncuuya form submit edilmelidir.   
 
 

İpucu

Repeat Döngüsünde Index Değerini Öğrenmek

ui:repeat elementinde döngüde index sayısı alınabilir. Bunun için varStatus elementi kullanılır. Kullanımı aşağıdaki gibidir:
<ui:repeat value="#{testBean.list}" var="item" varStatus="myVarStatus">
İndex Sayısı : #{myVarStatus.index}
</ui:repeat>

myVarStatus değişkeninden tek mi çift mi sırada olunduğu, ilk veya son satır olduğu gibi bilgilere de ulaşılabilir

İpucu

ResourceHandlerWrapper Kullanarak Resource Başına Domain Eklemek

JSF'de resource lar (css, js vb..) /javax.faces.resource/* şeklinde başlayacak şekilde header içine eklenmektedir.
Eğer sizin siteniz başka bir sitenin içinde iframe'de gösterilmek istendiğinde sorun çıkabilmektedir.
Bunun yerine bu resource'ları DOMAIN/javax.faces.resource/* şeklinde eklenmesini sağlayabilirsiniz.


Bu işlemi yapabilmek için ResourceHandlerWrapper extend edilmelidir. Örneğin sınıf aşağıdaki gibidir :


import javax.faces.application.*;
public class DomainResouceHandler extends ResourceHandlerWrapper {
	private ResourceHandler wrapped;
	public DomainResouceHandler(ResourceHandler wrapped) {
		this.wrapped = wrapped;
	}
	@Override
	public Resource createResource(final String resourceName, final String libraryName) {
		final Resource resource = super.createResource(resourceName, libraryName);
		return new ResourceWrapper() {
			@Override
			public String getRequestPath() {
                              return "http://example.com/"+resource.getRequestPath();
			}
			@Override
			public Resource getWrapped() {
				return resource;
			}
		};
	}
	@Override
	public ResourceHandler getWrapped() {
		return wrapped;
	}
}
DomainResouceHandler sınıfı ResourceHandlerWrapper'dan extend edilmiş ve createResource method'u override edilmiştir.
Yeni bir ResourceWrapper yaratılmış ve verilmiştir. Bu resource wrapper'da getRequestPath methodunun için değiştirilip domain eklenmiştir.
Bu şekilde http://example.com/javax.faces.resource/* şeklinde domain altından resource'ların yüklenmesi sağlanmıştır

Bu handler çalışması için aşağıdaki ifadenin faces-config.xml'de olması gerekiyor:
<application>
 		 <resource-handler>com.done.rabbit.support.resource.DomainResouceHandler</resource-handler>
 	</application>

İpucu

ViewHandlerWrapper Kullanarak Form Action Değerini Değiştirmek

JSF'de h:form elementi ile eklediğiniz formda , action değeri /sayfa_pathi şeklinde olmaktadır. Bunun yerine action ifadesini http://sizindomain/sayfapathi şeklinde değiştirebilmeniz mümkündür.
Örneğin www.example.com sitemizde /kayit/index.jsf sayfası olsun. Bu sayfanın formunun action'nda /kayit/index.jsf olacaktır. Bunun nedeni JSF framework'üdür. action ifadesinde http://www.example.com/kayit/index.jsf gözükmesini sağlayalım. Bunun için aşağıdaki ViewHandlerWrapper den türemiş bir sınıf eklemek gerekir :
package com.fibiler.test;
import javax.faces.application.*;
import javax.faces.context.*;
import javax.servlet.http.*;

public class CustomViewHandler extends ViewHandlerWrapper{

	private ViewHandler wrappped;
	public CustomViewHandler(ViewHandler wrappped) {
	    super();
	    this.wrappped = wrappped;
	}
	@Override
	public ViewHandler getWrapped() {
		return wrappped;
	}
	@Override
	public String getActionURL(FacesContext context, String viewId) {
		
		HttpServletRequest request=(HttpServletRequest)FacesContext.
getCurrentInstance().getExternalContext().getRequest();		
		String url=request.getRequestURL().toString();
				
		if(url==null){
			
			return super.getActionURL(context, viewId);
			
		}
		
		return "http://www.example.com"+super.getActionURL(context, viewId);
		
	}
}
Yukarıdaki kodda getActionURL method'u override edilmiş ve action URL'inin başına http://www.example.com eklenmiştir.
CustomViewHandler sınıfı tanımı faces-config.xml dosyasına aşağıdaki gibi eklenmelidir:
<application>
<view-handler>com.fibiler.test.CustomViewHandler</view-handler>
</application>
Bu işlemleri yaptıktan sonra /kayit/index.jsf sayfasına girip form elementinin action değerini kontrol ettiğinizde http://www.example.com//kayit/index.jsf değerini görmeniz gerekir.

İpucu

convertDateTime ile Tarih Biçimlendirme

JSF'de bir tarih alanını f: f:convertDateTime ile biçimlendirebilirsiniz. Biçimlendirirken time zone ve locale verebilirsiniz. Aşağıdaki örnek bir tarih ve saati Türkiye saatine göre ve gg.AA.yyyy olacak şekilde biçimli gözükmesini sağlamaktadır:
<h:outputText value="#{testBean.date}" >
<f:convertDateTime pattern="dd.MM.yyyy HH:mm"  timeZone="Turkey" locale="tr_TR"/>
</h:outputText>
testBean'deki date alanı, Türkiye saatine göre dd.MM.yyyy HH:mm şeklinde formatlı gözükür.

İpucu

Mamaged Bean'den Resource Bilgilerine Erişimek

Aşağıdaki gibi iki metot eklenirse Managed Bean'den resource mesajlarını alabilirsiniz :
protected ResourceBundle getBundle() {
	if (bundle == null) {
		FacesContext context = FacesContext.getCurrentInstance();
		bundle = context.getApplication().getResourceBundle(context, "msg");
	}
	return bundle;
}
protected String getMessage(String key, String defaultValue) {
	String result = null;
	try {
		result = getBundle().getString(key);
	} catch (MissingResourceException e) {
		return defaultValue;
	}
	return result;
}
gertMessage metoduna key ile resources dosyasından desteklenen Local'e göre bir değer alınabilir.
Metot aşağıdaki gibi parametre alacak şekilde değiştirilebilir. Mesajlarda {0} , {1} şeklinde parametre desteği verilmiş olunur.
protected String getMessage(String key, String defaultValue,
                            String... parameters) {
 
	String result = null;
	try {
		result = getBundle().getString(key);
		if(result!=null){
			return MessageFormat.format(result, parameters);
		}else{
			return result;
		}
	} catch (MissingResourceException e) {
		return defaultValue;
	}
             
}

Örnek

Bir String Listesi için Converter Örneği

Bir bean içindeki bir listeyi araya virgül koyarak göstermek ve araya virgül girilerek verilen bilgiyi liste olarak almak için aşağıdaki gibi bir converter yapılabilir.
import java.util.Arrays;
import java.util.List;
 
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
 
@FacesConverter(value = "com.fibiler.jsf.converter.ListConverter")
public class ListConverter implements Converter{
 
	@Override
	public Object getAsObject(FacesContext context, UIComponent component, String value) {
			   
		String[] values=value.split(",");

		return Arrays.asList(values);
			   
	}

	@Override"
	public String getAsString(FacesContext context, UIComponent component, Object value) {
			   
		List<String> list=(List)value;

		String joined = String.join(",", list);

		return joined;
			   
	}
 
}
Gelen değer , ile parçalanıp listeye çevrilmekte, ters olarak da gelen liste aralarına , eklenerek birleştirilmektedir. Aşağıdaki gibi bir bean ve xhtml ile kullanılabilir:
import java.util.ArrayList;
import java.util.List;
 
import javax.annotation.ManagedBean;
 
@ManagedBean
public class ListConverterTestBean {
             
	private List<String> items=new ArrayList<String>();

	public ListConverterTestBean() {
			   
		items.add("ITEM1");
		items.add("ITEM2");
		items.add("ITEM3");
			   
	}

	public List<String> getItems() {
		return items;
	}

	public void setItems(List<String> items) {
		this.items = items;
	}

	public void submit(){
			   
		for (String string : items) {
					 
			System.out.println("item :" + string);
					 
		}
			   
	}
}
Bu bean aşağıdaki gibi kullanılabilir:
<h:form>
 
	<h:inputText value="#{listConverterTestBean.items}" 
		converter="com.fibiler.jsf.converter.ListConverter"></h:inputText>

	<h:commandButton action="#{listConverterTestBean.submit}" 
		value="Submit"></h:commandButton>
             
</h:form>
Görüldüğü gibi converter="com.fibiler.jsf.converter.ListConverter" ile converter verilmiştir.

Örnek

SelectOneMenu ile Enum Kullanılan Bir Örnek

JSF'de bir sayfada enum değerlerini bir SelectOneMenu bileşenine yükleyebilirsiniz. Enum aşağıdaki gibi olsun:
public enum Test {
             
	ITEM1,
	ITEM2,
	ITEM3;
 
}
Bu enum kullanıldığı bean aşağıdaki gibi olsun :
import javax.faces.bean.ManagedBean;
import javax.faces.model.SelectItem;
 
@ManagedBean
public class EnumBean {
 
	private Test selected;
	public Test[] getEnums(){
			   
		return Test.values();
			   
	}
	public SelectItem[] getEnumsAsSelectItem() {
		SelectItem[] items = new SelectItem[Test.values().length];
		int i = 0;
		for(Test t: Test.values()) {
			items[i++] = new SelectItem(t, t.toString());
		}
		return items;
	}
	public String submit(){
			   
		System.out.println("selected value : " + selected);
		return "";
			   
	}
	public Test getSelected() {
		return selected;
	}
	public void setSelected(Test selected) {
		this.selected = selected;
	}
             
}
getEnums() ile Enum değeleri dizi olarak verilmektedir. İstenirse getEnumsAsSelectItem() ile de SelectItem listesi olarak alınabilir.
Form aşağıdaki gibidir :
<h:form>
 
	<h3>Enum Test 3</h3>
	<h:selectOneMenu value="#{enumBean.selected}">
		<f:selectItems value="#{enumBean.enums}"></f:selectItems>
	</h:selectOneMenu>
	<h:commandButton action="#{enumBean.submit}" value="Submit"></h:commandButton>
             
</h:form>
Submit düğmesine basıldığında console'de basılan elementin değeri gösterilir.
Enum'da title gibi bir başka özellik olabilir:
public enum Test {
             
	ITEM1("item 1"),
	ITEM2("item 2"),
	ITEM3("item 3");
	String title;
	Test(String title) {
		this.title = title;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
 
}
Eğer açılır listede title değerini göstermek istiyorsanız sayfada aşağıdaki gibi değişiklik yapabilirsiniz:
<h:selectOneMenu value="#{enumBean.selected}">
	<f:selectItems value="#{enumBean.enums}"
		var="t" itemLabel="#{t.title}" itemValue="#{t}"></f:selectItems>
</h:selectOneMenu>

Sayfada artık title alanı gözükecek , value olarak da enum'un kendisi kullanılacaktır.

Kavram

Flash Scope

Tanım: JSF'de özellikle sayfalar arasında kolay bir şekilde veri aktarımı sağlayan bir scope. Flash scope'e eklenen bir değer alındıktan sonra flash scope'ndan kaldırılır.

Veri

Project Stage Tanımlama ve Olabilecek Değerler

JSF'de olabilecek project stage değerleri aşağıdaki gibidir:
  • Production
  • Development
  • UnitTest
  • SystemTest
  • Extension
Bu değerler web.xml'de javax.faces.PROJECT_STAGE Development şeklinde kullanılabilir. Extension olarak belirtilen stage , geliştirici tarafından özelleştirilebilen bir stage'dir.

Veri

JSF'de Yorum

JSF'de bir bölümde HTML yorumunu (<!-- ve -->) kullanabilirsiniz:
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html">
		
	<h:form>
	
		<h:inputText value="test"></h:inputText>
		
		<!--  
		<h:inputText value="yorum içinde"></h:inputText>
		-->
	
	</h:form>

</html>
Ancak bu sayfa çalıştırıldığında yorum içinde yazılanlar sayfanın kodunda görünecektir. Yorum içindeki hiç bir şey sayfa kodunda gözülmesin istenirse aşağıdaki gibi bir parametre eklenmelidir. web.xml'e aşağıdaki gibi ekleme yapılabilir :
<context-param>
    <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
    <param-value>true</param-value>
</context-param>
JSF'nin eski versiyonlarında facelets.SKIP_COMMENTS şeklinde kullanılır. FACELETS_SKIP_COMMENTS eklendiğinde tüm yorumlar gözükmez. Bu durum kod içinde gelitiricilerin yorumlarının da sayfanın kodunun gözükmeyeceği anlamına gelir. FACELETS_SKIP_COMMENTS yerine ui:remove elementi de kulanılabilir :
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://java.sun.com/jsf/facelets">
		
	<h:form>
	
		<h:inputText value="test"></h:inputText>
		
		<ui:remove>
		<h:inputText value="yorum içinde"></h:inputText>
		</ui:remove>
	
	</h:form>

</html>

İpucu

Web Tarayıcısında Clipboard'a JSON Verisini Kopyalama

Bu iş için https://clipboardjs.com/ kütüphanesi kullanılmıştır. Ancak bu kütüphanenin örnekleri, Json verisi olan bir yazı alanı için çalışmamaktadır. Bunun için aşağıdaki gibi bir yöntem izlenmiştir.
Aşağıdaki örnek bir JSON verisini clipboarda kopyalamaktadır:
<input type="text" id="inputJson" value="" style="display:none"/>
<button type="button" 
	class="button" id="copy-button" data-clipboard-target="#inputJson">Copy To Clipboard</button>
<br/>
<h:outputText id="inputTextPretty" value="#{inventoryBean.pretty}" 
style="white-space: pre-wrap;"></h:outputText> 
<h:outputScript name="clipboard.min.js" library="js"></h:outputScript>
<script>
var clipboard = new ClipboardJS('.button', {
	text: function() {
		return JSON.stringify(#{testBean.json});
	}
});
</script>

inputJson id'li input alanı gizli olarak koyulmuştur. Kopyalayan düğme eklenmiştir. data-clipboard-target özelliği kopyalanacak alanı vermektedir. Ancak biz fonksiyonu script bölümünde görüldüğü gibi eziyoruz yani yazı alanına girilen değeri değil Bean'den gelen değeri kullanacağız. JSON verisi TestBean sınıfındadır ve #{testBean.json} ile alınmaktadır. Bu sınıf bir JSON string'i döndürür. JSON.stringify() ise dönen JSON ifadesini Javascript için Json nesnesine çevirir. Bu ifade ile bir JSON verisi clipboard'a aktarılmış olunur.
Eğer JSON yerine basit bir tipi clipboard'a atmak istiyorsanız fonksiyonu yazamanıza gerek yoktur. var clipboard = new ClipboardJS('.button') şeklinde vermeniz yeterlidir. inputJson girilen yazılan düğmeye tıklandığında clipboard'a eklenir.

Örnek

Tomcat 9 ve JSF 2.3 ile Bir Web Socket Örneği

Bu örnekte JSF 2.3'de "f:websocket" kullanılarak bir web socket örneği yaratılmıştır. Örnekte bir sayfadan mesaj gönderildiği zaman hem mesaj mesaj gönderilen sayfaya hem de ikinci bir sayfaya gelen mesaj sunucudan push edilmiştir.
Öcelikle aşağıdakiler bağımlılıkta olmalıdır :
<dependency>
	<groupId>java.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>4.0.0</version>
</dependency>
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>javax.faces</artifactId>
	<version>2.3.9</version>
</dependency>
<dependency>
	<groupId>javax.faces</groupId>
	<artifactId>javax.faces-api</artifactId>
	<version>2.3</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>javax.enterprise</groupId>
	<artifactId>cdi-api</artifactId>
	<version>1.2<version>
</dependency>
<dependency>
	<groupId>org.jboss.weld.servlet</groupId>
	<artifactId>weld-servlet</artifactId>
	<version>2.2.9.Final</version>
</dependency>
<dependency>
	<groupId>javax.json</groupId>
	<artifactId>javax.json-api</artifactId>
	<version>1.1.4</version>
</dependency>
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>javax.json</artifactId>
	<version>1.1.4</version>
</dependency>
java.lang.ClassNotFoundException: javax.json.Json
java.lang.ClassNotFoundException: org.glassfish.json.JsonProviderImpl hataları alıyorsanız javax.json ve javax.json-api bağımlılıklarını eklememişsiniz demektir.
Öncelikle girilen mesajı diğerlerine push eden bean yaratıyoruz :
import java.io.Serializable;
import javax.faces.push.Push;
import javax.faces.push.PushContext;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@ViewScoped
public class MessageBean implements Serializable {
	@Inject @Push
        private PushContext mypush;
	private String message;
	
	public void sendMessage() {
		mypush.send(message);
	}
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	
}
mypush, push enpoint'idir. sendMessage() yöntemi çağrıldığında gelen mesaj diğerler sayfalara gönderilir.
Mesaj üreten ve aynı zamanda dışarıdan gelen bir mesajı gösteren sayfa aşağıdaki gibidir :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns:h="http://java.sun.com/jsf/html" 
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
  <title>Socket</title>
</h:head>
<h:body>
<h:form>
	<script>
		function myMessageListener(message) {
			alert(message);
		}
	</script>
	
	<f:websocket channel="mypush" onmessage="myMessageListener"/>
	<h:inputText id="pushMessage" value="#{messageBean.message}"/>
	<br/>
	<h:commandButton action="#{messageBean.sendMessage}" value="Send Message"/>
	
</h:form>
</h:body>      
</html>
Yazı alanına mesajı yazıp Send Message düğmesine basılınca MessageBean'in sendMessage yöntemi çağrılır. Bu yöntemde socket açmış tüm sayfalara mesajı iletir.
Sadece gelen mesajı gösterecek ikinci sayfa aşağıdaki gibidir :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns:h="http://java.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<h:head>
  <title>Socket</title>
</h:head>
<h:body>
<h:form>
	<script>
		function myMessageListener(message) {
			alert(message);
		}
	</script>
	
	<f:websocket channel="mypush" onmessage="myMessageListener"/>
	
</h:form>
</h:body>      
</html>

İlk sayfada mesajı girip düğmeye basarsanız hem bulunduğunuz sayfada hem de diğer sayfada alert penceresinde girdiğiniz mesaj gözükecektir.

İpucu

JSF 2.3 ve Tomcat 9 ile Web Projesi Yaratmak

Burada Eclipse, JSF 2.3 ve Tomcat 9 kullanarak bir web projesi yaratıyoruz ve çalıştırıyoruz. Öncelikle JSF 2.3 için gereken bağımlıklar eklenmelidir. JSF 2.3 artık CDI gerekmesinden dolayı CDI apisi ve onun implemantasyonu olan Weld eklenmelidir :
<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>4.0.0</version>
</dependency>
<dependency>
	<groupId>javax.faces</groupId>
	<artifactId>javax.faces-api</artifactId>
	<version>2.3</version>
</dependency>
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>javax.faces</artifactId>
	<version>2.3.9</version>
</dependency>
<dependency>
	<groupId>javax.enterprise</groupId>
	<artifactId>cdi-api</artifactId>
	<version>1.2</version>
</dependency>
<dependency>
	<groupId>org.jboss.weld.servlet</groupId>
	<artifactId>weld-servlet</artifactId>
	<version>2.4.8.Final</version>
</dependency>
Ardından CDI için WEB-INF için beans.xml eklenir :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
	bean-discovery-mode="all" version="2.0">
</beans>
Ardından Tomcat 9 için META-INF altında context.xml eklenir :
<Context>
   <Resource name="BeanManager" 
      auth="Container"
      type="javax.enterprise.inject.spi.BeanManager"
      factory="org.jboss.weld.resources.ManagerObjectFactory"/>
</Context>
web.xml'e aşağıdaki eklenir :
<listener>
	<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
<resource-env-ref>
	<resource-env-ref-name>BeanManager</resource-env-ref-name>
	<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
</resource-env-ref>
web.xml'in son hali şu şekilde olmalı :
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>JSF2_3Test</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.xhtml</welcome-file> 
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
  
	<listener>
		<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
	</listener>
	<resource-env-ref>
		<resource-env-ref-name>BeanManager</resource-env-ref-name>
		<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
	</resource-env-ref>
	  
</web-app>
Artık ortam hazır demektir. En basit olarak aşağıdaki gibi bir index.xhtml sayfası yapalım :
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
   <head>
      <meta charset="ISO-8859-9"/>
      <title>Merhaba JSF 2.3</title>
   </head>
   <body>   
   		<h:outputText value="Merhaba JSF 2.3"></h:outputText>   
   </body>
</html>
Artık bu projeyi Tomcat 9'da çalıştırabiliriz. Bu projeyi çalıştırdığınızda aşağıdaki gibi hatalar alabilirsiniz :
Caused by: javax.faces.FacesException: Unable to find CDI BeanManager
	at com.sun.faces.application.ApplicationImpl.isJsf23(ApplicationImpl.java:2714)
	at com.sun.faces.application.ApplicationImpl.addELResolver(ApplicationImpl.java:549)
	at javax.faces.application.ApplicationWrapper.addELResolver(ApplicationWrapper.java:611)
	at org.jboss.weld.environment.servlet.jsf.WeldApplication.(WeldApplication.java:72)
	at org.jboss.weld.environment.servlet.jsf.WeldApplicationFactory.getApplication(WeldApplicationFactory.java:46)
	at com.sun.faces.application.InjectionApplicationFactory.getApplication(InjectionApplicationFactory.java:88)
	at com.sun.faces.config.InitFacesContext.getApplication(InitFacesContext.java:153)
	at com.sun.faces.lifecycle.ClientWindowFactoryImpl.(ClientWindowFactoryImpl.java:63)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at javax.faces.FactoryFinderInstance.getImplGivenPreviousImpl(FactoryFinderInstance.java:391)
	at javax.faces.FactoryFinderInstance.getImplementationInstance(FactoryFinderInstance.java:255)
	at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:529)
	at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:292)
	at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:354)
	... 33 more
java.lang.IllegalStateException: Could not find backup for factory javax.faces.application.ApplicationFactory. 
	at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:541)
	at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:292)
	at com.sun.faces.config.InitFacesContext.getApplication(InitFacesContext.java:152)
	at com.sun.faces.config.ConfigureListener.contextDestroyed(ConfigureListener.java:367)
	at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4722)
	at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5395)
	at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:257)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:187)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
	at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:841)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
	at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.StandardService.startInternal(StandardService.java:421)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:738)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:342)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473)
Bu durumda aşağıdaki gibi bir bean eklemek gerekir :
package com.fibiler.jsf2_3.hello;
import javax.faces.annotation.FacesConfig;
import javax.faces.annotation.FacesConfig.Version;
@FacesConfig(version = Version.JSF_2_3)
public class ConfigurationBean {
}
Bunu eklendikten sonra tomcat 9'u çalıştırırsanız hata gelmeyecektir. Hatanız sebebi projenizde bir bean olmamasıdır. Yukarıdaki ConfigurationBean'i eklemek yerine aşağıdaki gibi bir bean yapıp onu kullanalım:
import javax.inject.Named;
@Named
public class HelloBean {
	
	private String message="Merhaba JSF 2.3";
	
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
}
Sayfa şu şekilde olacak :
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
   <head>
      <meta charset="ISO-8859-9"/>
      <title>Merhaba JSF 2.3</title>
   </head>
   <body>   
   		<h:outputText value="#{helloBean.message}"></h:outputText>   
   </body>
</html>
Artık proje hata vermeyecektir. .

İpucu

Tomcat 10 ile JSF 3.0 ile Web Projesi

Tomcat 10, Jakarta 9 desteklemektedir. Jakarta 9 için JSF 3.0 kullanılmaktadır.
Tomcat 10 üzerinde JSF 3.0 projesi yapıyoruz. Öncelikle pom.xml'e aşağıdaki bağımlılıklar eklenir:
<dependency>
	<groupId>jakarta.faces</groupId>
	<artifactId>jakarta.faces-api</artifactId>
	<version>3.0.0</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>jakarta.faces</artifactId>
	<version>3.0.1</version>
</dependency>
<dependency>
	<groupId>jakarta.servlet</groupId>
	<artifactId>jakarta.servlet-api</artifactId>
	<version>5.0.0</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>jakarta.servlet.jsp</groupId>
	<artifactId>jakarta.servlet.jsp-api</artifactId>
	<version>3.0.0</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>jakarta.el</groupId>
	<artifactId>jakarta.el-api</artifactId>
	<version>4.0.0</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>org.jboss.weld.servlet</groupId>
	<artifactId>weld-servlet-shaded</artifactId>
	<version>4.0.0.Final</version>
</dependency>
Tomcat 9, Jakarta EE 9'u desteklemektedir. Bu nedenle Jakarta kullanılmaktadır. Weld kütüphanesi CDI için eklenmektedir. CDI için META-INF klasörü altında context.xml eklenir:
<Context>
    <Resource name="BeanManager" 
        auth="Container"
        type="jakarta.enterprise.inject.spi.BeanManager"
        factory="org.jboss.weld.resources.ManagerObjectFactory" />
</Context>
Ardından WEB-INF altına boş bir beans.xml dosyası konulur:
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_3_0.xsd"
       bean-discovery-mode="all">
</beans>
Web.xml aşağıdaki gibi olsun :
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
	id="WebApp_ID" version="4.0">
	<display-name>web</display-name>
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
</web-app>
faces-config.xml ise aşağıdaki gibidir :
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_3_0.xsd"
    version="3.0">
</faces-config>
Artık bir Bean yaratabiliriz :
package com.test;
import jakarta.inject.Named;
@Named
public class HelloBean {
	
	  private String message="Merhaba JSF 3.0";
	   
	  public String getMessage() {
	    return message;
	  }
	  public void setMessage(String message) {
	    this.message = message;
	  }
}
Bu bean'i kullanan bir sayfa yapalım :
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Hello JSF 3.0</title>
    </h:head>
    <h:body>
        <h1>#{helloBean.message}</h1>
    </h:body>
</html> 

Tomcat 10'da bu proje deploy edilip çalıştırıldığında ekranda Merhaba JSF 3.0 yazısı görülecektir.
Proje kodlarına buradan ulaşabilirsiniz : Proje Kodları İçin



Bu Sayfayı Paylaş:

İletişim Bilgileri

Takip Et

Her Hakkı Saklıdır. Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir. Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir