<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
> <channel><title>Des Geeks et des lettres &#187; Programmation</title> <atom:link href="http://desgeeksetdeslettres.com/blog/category/programmation-java/feed" rel="self" type="application/rss+xml" /><link>http://desgeeksetdeslettres.com/blog</link> <description>Un blog numérique à lire !</description> <lastBuildDate>Mon, 21 May 2012 22:06:31 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3</generator> <item><title>Accepter ou rejeter automatiquement vos amis sur Facebook</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/accepter-ou-rejeter-automatiquement-amis-facebook</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/accepter-ou-rejeter-automatiquement-amis-facebook#comments</comments> <pubDate>Mon, 21 May 2012 16:47:22 +0000</pubDate> <dc:creator>Greg</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[facebook]]></category> <category><![CDATA[javascript]]></category> <category><![CDATA[réseau social]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2770</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/accepter-ou-rejeter-automatiquement-amis-facebook"><img
align="left" hspace="5" width="155" src="http://desgeeksetdeslettres.s3.amazonaws.com/icon-fb.png" class="alignleft wp-post-image tfe" alt="icone facebook" title="" /></a>Je cherchais à accepter automatiquement tous les éventuels amis qui s'inscriraient par la suite.]]></description> <content:encoded><![CDATA[<p></p><p
style="text-align: justify;">C&#8217;est peut-être bête, mais il y a des fois où on cherche un truc tout bête, qui nous faciliterait la vie, mais qui nous bloque parce qu&#8217;on ne sait pas comment s&#8217;y prendre. C&#8217;est tout l&#8217;intérêt des programmeurs que de chercher ce genre de petites bêtes afin de les résoudre et d&#8217;ajouter sa petite pierre à l&#8217;humanité <img
src='http://desgeeksetdeslettres.com/blog/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /></p><p
style="text-align: justify;"><img
class="aligncenter" src="http://desgeeksetdeslettres.s3.amazonaws.com/icon-fb.png" alt="icone facebook" width="72" height="72" /></p><p
style="text-align: justify;">Pour ma part, je ne suis pas un pro de Facebook et je cherchais à accepter automatiquement tous les éventuels amis qui s&#8217;inscrirait par la suite. Cela peut se révéler utile pour celui qui a plusieurs comptes Facebook, cela lui évite de devoir, à chaque fois, se connecter avec des login et des mots de passe différents.</p><p
style="text-align: justify;">J&#8217;ai fini par tomber sur la technique suivante :</p><ul><li>Se rendre sur <a
href="http://www.facebook.com/reqs.php">http://www.facebook.com/reqs.php</a></li><li>copier ce bout de code dans votre barre d&#8217;adresse :</li><li>javascript:for( i = 1;i&lt;document.getElementsByName(&laquo;&nbsp;actions[accept]&laquo;&nbsp;).length;i++){document.getElementsByName(&laquo;&nbsp;actions[accept]&laquo;&nbsp;)[i].click();}void(0);</li><li>pour les utilisateurs de Google chrome, penser à réécrire &laquo;&nbsp;javascript:&nbsp;&raquo; avant d&#8217;appuyer sur Entrée, parce que ça disparaît</li></ul><p
style="text-align: justify;">Normalement ça devrait marcher, je l&#8217;espère du moins, je vous dis ça dès que j&#8217;ai un retour.</p><p
style="text-align: justify;">PS :</p><p
style="text-align: justify;">Pour rejeter automatiquement les invitations, c&#8217;est ce code-là qu&#8217;il faut utiliser :</p><p
style="text-align: justify;"><code>javascript:for( i = 1;i&lt;document.getElementsByName("actions[hide]").length;i++){document.getElementsByName("actions[hide]")[i].click();}void(0);</code></p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/accepter-ou-rejeter-automatiquement-amis-facebook/feed</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Google url shortener API : Exemple d&#8217;utilisation en Java</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/google-url-shortener-api-exemple-dutilisation-en-java</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/google-url-shortener-api-exemple-dutilisation-en-java#comments</comments> <pubDate>Wed, 09 May 2012 22:15:11 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[goo.gl]]></category> <category><![CDATA[google]]></category> <category><![CDATA[google url shortener api]]></category> <category><![CDATA[réduction d'url]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2765</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/google-url-shortener-api-exemple-dutilisation-en-java"><img
align="left" hspace="5" width="155" height="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/05/shorten-google-map-URL-150x150.jpg" class="alignleft wp-post-image tfe" alt="" title="google url shortener" /></a>Google url shortener est le service lancé en 2010 par Google qui permet de réduire vos longues urls en urls très courtes, le premier service de ce type date de 2001 et l&#8217;un des plus connus à ce jour reste TinyURL qui date de 2002. Si vous souhaitez réduire vos urls par Google il faut [...]]]></description> <content:encoded><![CDATA[<p></p><p><a
href="http://goo.gl/">Google url shortener</a> est le service lancé en 2010 par Google qui permet de réduire vos longues urls en urls très courtes, le premier service de ce type date de 2001 et l&#8217;un des plus connus à ce jour reste <a
href="http://tinyurl.com/">TinyURL</a> qui date de 2002.</p><p>Si vous souhaitez réduire vos urls par Google il faut donc se rendre sur le site, saisir l&#8217;url à réduire, cliquer sur un bouton et hop, l&#8217;url correspondante raccourcie apparaît, vous n&#8217;avez plus qu&#8217;à la copier pour l&#8217;utiliser où bon vous semble (<a
href="http://fr.wikipedia.org/wiki/R%C3%A9duction_d'URL#Critiques">quelques réserves</a>).</p><p>Qu&#8217;en est-il si vous voulez proposer à vos utilisateurs la réduction d&#8217;url par Google directement depuis votre application ou site web ?</p><p
style="text-align: center;"><a
href="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/05/shorten-google-map-URL.jpg"><img
class="aligncenter  wp-image-2766" title="google url shortener" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/05/shorten-google-map-URL.jpg" alt="" width="360" height="291" /></a></p><p>Depuis le début d&#8217;année 2012, Google propose une API nous permettant d&#8217;utiliser ce service en le programmant, <a
href="https://developers.google.com/url-shortener/libraries">sur cette page</a> vous verrez un exemple d&#8217;utilisation selon votre langage, cependant la méthode proposée en Java me semble peu pratique et compliquée, d&#8217;autant plus qu&#8217;elle nécessite l&#8217;utilisation de nombreux jars.</p><p>Je vais donc vous proposer la façon que j&#8217;ai choisie pour utiliser de façon simple l&#8217;API de Google url shortener :</p><ol><li>le paramètre key=API_key n&#8217;est pas obligatoire à la fin de l&#8217;url, cependant il est nécessaire si vous souhaitez connaître suivre les reports et statistiques sur votre <a
href="https://code.google.com/apis/console">console Google apis</a></li><li>seule la bibliothèque Jackson est nécessaire (vous pouvez en utiliser une autre) pour parser le flux JSON reçue par l&#8217;appel du service Google</li></ol><pre class="brush: java">import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import org.codehaus.jackson.map.ObjectMapper;
public class ShortenerUrlUtil {
	public static final String GOOGLE_SHORTENER_URL = "https://www.googleapis.com/urlshortener/v1/url?key=API_key";
	public static String shortenUrl(String longUrl) {
		String data = "{\"longUrl\": \"" + longUrl + "\"}";
		try {
			// création d'une connection HTTP
			URL url = new URL(GOOGLE_SHORTENER_URL);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("POST");
			connection.setDoOutput(true);
			connection.setRequestProperty("Content-Type", "application/json");
			// appel de l'API
			OutputStreamWriter output = new OutputStreamWriter(connection.getOutputStream());
			output.write(data);
			output.flush();
			// réception de la réponse au format JSON
			BufferedReader response = new BufferedReader(new InputStreamReader(connection.getInputStream()));
			String result = "";
			String line;
			while ((line = response.readLine()) != null) {
				result += line;
			}
			// interprétation du flux JSON pour extraire l'url réduite
			ObjectMapper mapper = new ObjectMapper();
			Map map = mapper.readValue(result, Map.class);
			output.close();
			response.close();
			return (String) map.get("id");
		} catch (Exception e) {
			return longUrl;
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		System.out.println(shortenUrl("http://magicsupremacy.fr/#!/deck"));
	}
}</pre>]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/google-url-shortener-api-exemple-dutilisation-en-java/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Utilisation de jTable.js avec traitement côté serveur en Java</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/utilisation-de-jtable-js-avec-traitement-cote-serveur-en-java</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/utilisation-de-jtable-js-avec-traitement-cote-serveur-en-java#comments</comments> <pubDate>Fri, 27 Apr 2012 10:06:02 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[jackson]]></category> <category><![CDATA[java]]></category> <category><![CDATA[json]]></category> <category><![CDATA[jtable]]></category> <category><![CDATA[spring]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2757</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/utilisation-de-jtable-js-avec-traitement-cote-serveur-en-java"><img
align="left" hspace="5" width="155" height="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/04/jtable-overview-150x150.png" class="alignleft wp-post-image tfe" alt="" title="jtable-overview" /></a>Nous ne parlerons pas du composant Swing JTable dans ce billet mais plutôt du plugin jQuery jTable qui permet de générer, à partir de données au format JSON, des tableaux riches et ajaxifiés proposant toutes les fonctionnalités d&#8217;un CRUD sans avoir à écrire une ligne d&#8217;HTML ou de JavaScript. Les points intéressants Voici rapidement les [...]]]></description> <content:encoded><![CDATA[<p></p><p>Nous ne parlerons pas du <a
href="http://docs.oracle.com/javase/1.5.0/docs/api/javax/swing/JTable.html">composant Swing JTable</a> dans ce billet mais plutôt du <a
href="http://www.jtable.org">plugin jQuery jTable</a> qui permet de générer, à partir de données au format JSON, des tableaux riches et ajaxifiés proposant toutes les fonctionnalités d&#8217;un CRUD sans avoir à écrire une ligne d&#8217;HTML ou de JavaScript.</p><p><img
class="aligncenter size-full wp-image-2758" title="jtable-overview" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/04/jtable-overview.png" alt="" width="580" height="332" /></p><h2>Les points intéressants</h2><p>Voici rapidement les principales qualité de ce plugin :</p><ul><li>Génère le source HTML de votre tableau et charge les données à afficher depuis votre serveur en AJAX</li><li>Crée automatiquement les actions &laquo;&nbsp;ajouter&nbsp;&raquo;, &laquo;&nbsp;supprimer&nbsp;&raquo; et &laquo;&nbsp;modifier&nbsp;&raquo; qui ouvrent une popup Dialog jQuery UI en envoyant l&#8217;information du changement au serveur en Ajax et en rafraîchissant le tableau dans le même temps</li><li>Supporte la pagination et le tri des colonnes côté serveur avec AJAX</li><li>Permet aux utilisateurs de sélectionner une ou plusieurs lignes du tableau et de modifier à la volée les tailles des colonnes</li><li>Plusieurs thèmes sont disponibles pour vos tableaux, il est simple de fabriquer soit-même son thème en jouant avec le fichier CSS</li><li>Fonctionne sur l&#8217;ensemble des navigateurs et ne dépend pas d&#8217;une technologie côté serveur, tant que les données sont renvoyées au format JSON</li><li>Expose certains évènement lors de la validation des formulaires et permet l&#8217;internationalisation simplement</li></ul><h2>Traitement serveur en Java</h2><p>Les exemples fournis dans <a
href="http://www.jtable.org/GettingStarted">la documentation en ligne</a> du plugin nous montrent une utilisation avec .NET et PHP, j&#8217;ai donc tenté l&#8217;expérience en Java en utilisant Spring MVC 3.1 et Jackson 1.9.6 pour la lecture et l&#8217;écriture en JSON.</p><p>Etant donné que les données qui transitent entre le client et le serveur sont au format JSON, je n&#8217;ai eu aucune difficulté à utiliser jTable.js dans une application JavaEE :</p><pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html lang="fr"&gt;
	&lt;head&gt;
		&lt;meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"&gt;
		&lt;title&gt;Utilisation de jTable.js avec Java&lt;/title&gt;
		&lt;link type="text/css" rel="stylesheet" media="all" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/ui-darkness/jquery-ui.css"/&gt;
		&lt;link type="text/css" rel="stylesheet" media="all" href="${pageContext.request.contextPath}/static/stylesheet/jtable/themes/standard/blue/jtable_blue.css"/&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;div id="FourriereTableContainer"&gt;&lt;/div&gt;
	&lt;/body&gt;
	&lt;script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"&gt;&lt;/script&gt;
	&lt;script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.ui/1.8.18/jquery-ui.min.js"&gt;&lt;/script&gt;
	&lt;script type="text/javascript" src="${pageContext.request.contextPath}/static/javascript/jquery.jtable.js"&gt;&lt;/script&gt;
	&lt;script&gt;
		$('#FourriereTableContainer').jtable({
			title: 'Liste des Fourrières',
			actions: {
				listAction: '${pageContext.request.contextPath}/jtable/list',
				createAction: '${pageContext.request.contextPath}/jtable/create',
				updateAction: '${pageContext.request.contextPath}/jtable/update',
				deleteAction: '${pageContext.request.contextPath}/jtable/delete'
			},
			fields: {
				id: {
					key: true,
					create: false,
					edit: false,
					list: false
				},
				nom: {
					title: 'Nom',
					width: '25%'
				},
				adresse: {
					title: 'Adresse',
					width: '25%'
				},
				ville: {
					title: 'Ville',
					width: '25%'
				},
				codePostal: {
					title: 'Code postal',
					width: '25%'
				}
			}
		});
		$('#FourriereTableContainer').jtable('load');
	&lt;/script&gt;
&lt;/html&gt;</pre><p>Voici en détail le contenu du contrôleur Spring derrière l&#8217;action /jtable/list qui permet de retourner les données JSON (avec Jackson) pour que jTable génère un joli tableau :</p><pre class="brush: java">@RequestMapping(value="/jtable/list", method=RequestMethod.GET)
@ResponseBody
public List listFourrieres() {
	FourriereJtable fourriereJtable = new FourriereJtable();
	// normalement ici appel à votre service métier qui va interroger votre base de données
	Fourriere fourriere1 = new Fourriere(1, "Nom1", "Adresse1", "Ville1", "CodePostal1");
	Fourriere fourriere2 = new Fourriere(2, "Nom2", "Adresse2", "Ville2", "CodePostal2");
	Fourriere fourriere3 = new Fourriere(3, "Nom3", "Adresse3", "Ville3", "CodePostal3");
	List records = new ArrayList();
	records.add(fourriere1);
	records.add(fourriere2);
	records.add(fourriere3);
	fourriereJtable.setResult("OK");
	fourriereJtable.setRecords(records);
	return fourriereJtable;
}</pre><h2>Attention aux Majuscules</h2><p>Le seul problème est que jTable requiert une majuscule à la première lettre des clés formant le message JSON :</p><pre class="brush: javascript">{
 "Result":"OK",
 "Records":[
  {"id":1,"nom":"Benjamin Button","adresse":"17 rue baudin","ville":"levallois", "codePostal","75000"}
 ]
}</pre><p>Or il me semble que la norme JSON impose des minuscules au niveau des clés du message, en tout cas c&#8217;est ce que fait <a
href="http://jackson.codehaus.org/">Jackson</a> automatiquement et d&#8217;autres bibliothèques Java comme <a
href="http://json-lib.sourceforge.net/">Json-lib</a> ou <a
href="http://code.google.com/p/json-simple/">Json-simple</a>.</p><p>Voici donc ce que Spring et Jackson génère en sortie et qui ne plait pas à jTable.js (&laquo;&nbsp;result&nbsp;&raquo; au lieu de &laquo;&nbsp;Result&nbsp;&raquo;, &laquo;&nbsp;records&nbsp;&raquo; au lieu de &laquo;&nbsp;Records&nbsp;&raquo;) :</p><pre class="brush: javascript">{
 "result":"OK",
 "records":[
  {"id":1,"nom":"Benjamin Button","adresse":"17 rue baudin","ville":"levallois", "codePostal","75000"}
 ]
}</pre><p>Je n&#8217;ai pas trouvé d&#8217;autre moyen que de modifier le code JavaScript de jTable.js directement, en changeant data.Result en data.result, data.Records en data.records et data.Message en data.message.</p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/utilisation-de-jtable-js-avec-traitement-cote-serveur-en-java/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Validation automatique des données avec HTML5 et Spring3</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/validation-automatique-des-donnees-saisies-avec-html5-et-spring3</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/validation-automatique-des-donnees-saisies-avec-html5-et-spring3#comments</comments> <pubDate>Mon, 16 Apr 2012 16:57:32 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[formulaire]]></category> <category><![CDATA[html5]]></category> <category><![CDATA[spring3]]></category> <category><![CDATA[validation]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2750</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/validation-automatique-des-donnees-saisies-avec-html5-et-spring3"><img
align="left" hspace="5" width="155" height="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/04/380x285-cz5t-150x150.jpg" class="alignleft wp-post-image tfe" alt="" title="Assemblage d" /></a>J&#8217;ai appris il y a longtemps qu&#8217;il était toujours nécessaire de contrôler et valider les données saisies par vos utilisateurs, du côté client comme du côté serveur (en HTML/JavaScript et en Java pour ma part), car généralement les erreurs ou les attaques viennent de là. Je n&#8217;ai jamais apprécié personnellement cette partie du travail car [...]]]></description> <content:encoded><![CDATA[<p></p><p>J&#8217;ai appris il y a longtemps qu&#8217;il était toujours nécessaire de contrôler et valider les données saisies par vos utilisateurs, du côté client comme du côté serveur (en HTML/JavaScript et en Java pour ma part), car généralement les erreurs ou les attaques viennent de là. Je n&#8217;ai jamais apprécié personnellement cette partie du travail car c&#8217;est à chaque fois la même chose et à chaque fois on doit tout refaire à la main &#8230;</p><p><img
class="aligncenter size-full wp-image-2751" title="Assemblage d'un puzzle" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/04/380x285-cz5t.jpg" alt="" width="380" height="285" /></p><h2>Validation côté client (HTML5)</h2><p>Avec HTML5 la validation de surface se fait déjà plus aisément, les nombreux &laquo;&nbsp;type&nbsp;&raquo; paramétrable dans nos champs de saisie limitent considérablement la saisie au mauvais format, exemple : &lt;input type=email&gt;, &lt;input type=date&gt;, &lt;input type=number&gt;, &lt;input type=color&gt; &#8230; (<a
href="http://miketaylr.com/code/input-type-attr.html" target="_blank">liste complète ici</a> avec support des différents navigateurs).</p><p>Ensuite de nouveaux attributs ont vu le jour comme required, min, max, list &#8230; qui nous évitent de devoir contrôler que le champ est bien saisi, qu&#8217;il est compris dans un intervalle donné ou bien qu&#8217;il fait partie d&#8217;une liste prédéfinie de valeurs.</p><pre class="brush: html">&lt;form action="" method="post"&gt;
&lt;input type="email" name="email" placeholder="Votre email" autofocus="autofocus" required="required" maxlength="100" size="50"/&gt;
&lt;input type="password" name="password" placeholder="Votre mot de passe" required="required" size="50"/&gt;
&lt;input type="number" name="age" placeholder="Votre age" required="required" size="25" min="18"/&gt;
&lt;/form&gt;</pre><p>Dans mon nouveau projet j&#8217;utilise HTML5 comme validateur client de surface plutôt que JavaScript.</p><p>Les données envoyées au serveur sont au format JSON, la transformation de mon formulaire en objet JSON est faite avec <a
href="https://github.com/maxatwork/form2js" target="_blank">form2js</a> et l&#8217;envoi se fait avec <a
href="http://jquery.com/" target="_blank">jQuery</a> de la façon suivante :</p><pre class="brush: javascript">&lt;script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://raw.github.com/maxatwork/form2js/master/src/form2js.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://raw.github.com/maxatwork/form2js/master/src/jquery.toObject.js"&gt;&lt;/script&gt;
$("form").submit(function(event) {
	var action = $(this).attr('action');
	var formAsObject = $(this).toObject(); // form2js
	$.ajax({
		url: action,
		type: "post",
		data: formAsObject,
		dataType: 'json',
		success: function(jsonFromServer) {
			// callback du serveur
		}
	});
	return false;
});</pre><p><em>A retenir : il faut utiliser la méthode &laquo;&nbsp;submit&nbsp;&raquo; de jQuery sur le formulaire plutôt que la méthode &laquo;&nbsp;on&nbsp;&raquo; ou &laquo;&nbsp;bind&nbsp;&raquo; sur le bouton submit car sinon la validation des données en HTML5 ne se fera pas.</em></p><h2>Validation côté serveur (Spring3)</h2><p>C&#8217;est là que Spring3 entre en jeu ainsi que ses nombreuses annotations qui nous facilitent la tâche, dans notre cas je parle de @ModelAttribute et @Validated.</p><pre class="brush: java">@RequestMapping(value="/login", method=RequestMethod.POST)
@ResponseBody
public UserModel login(@Validated({ UserLoginGroup.class }) @ModelAttribute UserModel user, BindingResult result, HttpServletRequest request, HttpServletResponse response) {
	// validation de surface faite avec @annotations
	if (result.hasErrors()) {
		// des erreurs de validation
	} else {
		// aucune erreur de validation en surface
	}
}</pre><p>La première (@ModelAttribute) permet de transformer automatiquement l&#8217;objet json envoyé par notre requête Ajax en objet Java : chaque attribut de l&#8217;objet json ayant le même nom (case sensitive) qu&#8217;un attribut de l&#8217;objet Java sera récupéré automatiquement.</p><p>La seconde (@Validated) indique que l&#8217;objet annoté doit être validé, la validation est écrite uniquement via des annotations, il en va de même pour les messages d&#8217;erreur à retourner. J&#8217;utilise les annotations de <a
href="http://www.hibernate.org/subprojects/validator.html" target="_blank">Hibernate Validator</a> qui offrent un plus grand choix, allant de @Email à @NotBlank en passant par @Future pour valider que la date saisie est dans le futur.</p><p>Malheureusement il n&#8217;existe encore aucun moyen nativement de comparer deux attributs de l&#8217;objet à valider, par exemple &laquo;&nbsp;email&nbsp;&raquo; et &laquo;&nbsp;emailConfirm&nbsp;&raquo; ou encore &laquo;&nbsp;password&nbsp;&raquo; et &laquo;&nbsp;passwordConfirm&nbsp;&raquo;, la communauté s&#8217;en est chargé en créant une annotation maison &laquo;&nbsp;FieldMatch&nbsp;&raquo; que j&#8217;utilise et qui marche à merveille, <a
href="http://stackoverflow.com/questions/1972933/cross-field-validation-with-hibernate-validator-jsr-303" target="_blank">voici le lien vers cette annotation</a>.</p><p>Vous l&#8217;avez compris, avec Spring3 la validation côté serveur est rendue très simple, voici un copier coller d&#8217;un objet que je valide automatiquement avec cette méthode :</p><pre class="brush: java">@FieldMatch.List({
    @FieldMatch(first = "password", second = "passwordConfirm", message = "Votre confirmation de mot de passe est invalide", groups = { UserRegisterGroup.class }),
    @FieldMatch(first = "email", second = "emailConfirm", message = "Votre confirmation d'email est invalide", groups = { UserRegisterGroup.class })
})
public class UserModel implements Serializable {
	private static final long serialVersionUID = -6014837207296264624L;
	@NotBlank(message = "Votre email est obligatoire", groups = { UserLoginGroup.class, UserRegisterGroup.class, UserLostPasswordGroup.class })
	@Email(message = "Votre email a un format incorrect", groups = { UserLoginGroup.class, UserRegisterGroup.class, UserLostPasswordGroup.class })
	@Length(min=3, max=100, message = "Votre email doit faire entre 3 et 100 caractères", groups = { UserLoginGroup.class, UserRegisterGroup.class, UserLostPasswordGroup.class })
	private String email;
	// FieldMatch suffit pour les contrôles
	private String emailConfirm;
	@NotBlank(message = "Votre mot de passe est obligatoire", groups = { UserLoginGroup.class, UserRegisterGroup.class })
	@Length(min=6, max=100, message = "Votre mot de passe doit faire entre 6 et 100 caractères", groups = { UserLoginGroup.class, UserRegisterGroup.class })
	private String password;
	// FieldMatch suffit pour les contrôles
	private String passwordConfirm;
	...
}</pre>]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/validation-automatique-des-donnees-saisies-avec-html5-et-spring3/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Configuration de base d&#8217;un projet Spring MVC et JPA avec Annotations</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/configuration-de-base-dun-projet-spring-mvc-et-jpa-avec-annotations</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/configuration-de-base-dun-projet-spring-mvc-et-jpa-avec-annotations#comments</comments> <pubDate>Mon, 19 Mar 2012 21:01:23 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[annotations]]></category> <category><![CDATA[eclipse]]></category> <category><![CDATA[java]]></category> <category><![CDATA[jpa]]></category> <category><![CDATA[spring mvc]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2728</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/configuration-de-base-dun-projet-spring-mvc-et-jpa-avec-annotations"><img
align="left" hspace="5" width="155" height="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/03/AppLayers-SpringMVC-150x150.jpg" class="alignleft wp-post-image tfe" alt="" title="AppLayers-SpringMVC" /></a>J&#8217;ai toujours été retissant à l&#8217;idée d&#8217;utiliser des annotations dans un projet, j&#8217;ai toujours manipulé des fichiers de configurations XML et l&#8217;idée d&#8217;ajouter de la configuration dans mes classes Java m&#8217;a toujours semblé contre-nature. Cependant tous les échos positifs entendus autour de moi quant à l&#8217;utilisation des Annotations m&#8217;ont fait franchir le pas ce week-end en démarrant [...]]]></description> <content:encoded><![CDATA[<p></p><p>J&#8217;ai toujours été retissant à l&#8217;idée d&#8217;utiliser des annotations dans un projet, j&#8217;ai toujours manipulé des fichiers de configurations XML et l&#8217;idée d&#8217;ajouter de la configuration dans mes classes Java m&#8217;a toujours semblé contre-nature.</p><p>Cependant tous les échos positifs entendus autour de moi quant à l&#8217;utilisation des Annotations m&#8217;ont fait franchir le pas ce week-end en démarrant un nouveau projet perso full annotations avec Spring MVC et JPA. Voici la façon dont je m&#8217;y suis pris pour configurer un tel projet.</p><p><img
class="aligncenter size-full wp-image-2729" title="AppLayers-SpringMVC" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/03/AppLayers-SpringMVC.jpg" alt="" width="442" height="299" /></p><h2>Environnement</h2><p>Voici l&#8217;état des lieux des technologies utilisées et de mon environnement de travail :</p><ul><li>Eclipse Helios SR2</li><li>Java 6.0 update 25</li><li>Tomcat 7.0</li><li>Spring 3.1.1</li><li>Hibernate 4.1.1</li><li>MySQL 5.5.8</li><li>JSTL 1.2 et Jackson 1.9.5 (pas utile pour la configuration de base)</li></ul><div><img
class="aligncenter size-full wp-image-2731" title="spring mvc - jpa - lib" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/03/spring-mvc-jpa-lib.png" alt="" width="440" height="935" /></div><h2>Configuration XML</h2><p>Finalement tout se joue au niveau des fichiers de configuration XML pour une bonne utilisation des annotations que ce soit côté web ou côté service/persistence, rien de bien compliqué en soit, mais il existe tellement de version possible sur la toile qu&#8217;il est vite facile de se tromper ou de copier coller n&#8217;importe quoi.</p><ul><li>web.xml <em>(src/main/webapp/WEB-INF/web.xml)</em></li></ul><pre class="brush: xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&gt;
	&lt;display-name&gt;Patati Patata&lt;/display-name&gt;
	&lt;!-- The definition of the Root Spring Container shared by all Servlets and Filters --&gt;
	&lt;context-param&gt;
        &lt;description&gt;Spring configuration file&lt;/description&gt;
        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
        &lt;param-value&gt;classpath:spring/applicationContext.xml&lt;/param-value&gt;
	&lt;/context-param&gt;
	&lt;!-- Creates the Spring Container shared by all Servlets and Filters --&gt;
	&lt;listener&gt;
        &lt;description&gt;Spring Loader&lt;/description&gt;
        &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
	&lt;/listener&gt;
	&lt;!-- Processes application requests --&gt;
	&lt;servlet&gt;
		&lt;description&gt;Spring MVC&lt;/description&gt;
        &lt;servlet-name&gt;spring-mvc&lt;/servlet-name&gt;
		&lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
		&lt;init-param&gt;
			&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
			&lt;param-value&gt;classpath:spring/applicationContext-web.xml&lt;/param-value&gt;
		&lt;/init-param&gt;
		&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
	&lt;/servlet&gt;
	&lt;servlet-mapping&gt;
		&lt;servlet-name&gt;spring-mvc&lt;/servlet-name&gt;
		&lt;url-pattern&gt;/&lt;/url-pattern&gt;
	&lt;/servlet-mapping&gt;
&lt;/web-app&gt;</pre><ul><li>applicationContext.xml <em>(src/main/config/spring/applicationContext.xml)</em></li></ul><pre class="brush: xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"&gt;
	&lt;!-- Annotations Scan --&gt;
	&lt;context:annotation-config/&gt;
	&lt;context:component-scan base-package="fr.patati.patata.service, fr.patati.patata.persistence" /&gt;
	&lt;!-- Entity Manager Factory --&gt;
	&lt;bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
		&lt;property name="persistenceUnitName" value="monAppliPU" /&gt;
	&lt;/bean&gt;
	&lt;!-- Transaction Manager --&gt;
	&lt;bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"&gt;
		&lt;property name="entityManagerFactory" ref="entityManagerFactory" /&gt;
	&lt;/bean&gt;
	&lt;!-- Transaction Annotations --&gt;
	&lt;tx:annotation-driven proxy-target-class="true" /&gt;
	&lt;tx:annotation-driven transaction-manager="transactionManager" /&gt;
&lt;/beans&gt;</pre><ul><li>applicationContext-web.xml <em>(src/main/config/spring/applicationContext-web.xml)</em></li></ul><pre class="brush: xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans:beans xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"&gt;
	&lt;!-- Enables the Spring MVC @Controller programming model --&gt;
	&lt;mvc:annotation-driven /&gt;
	&lt;!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --&gt;
	&lt;beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
		&lt;beans:property name="prefix" value="/WEB-INF/views/" /&gt;
		&lt;beans:property name="suffix" value=".jsp" /&gt;
	&lt;/beans:bean&gt;
	&lt;context:component-scan base-package="fr.patati.patata.web" /&gt;
&lt;/beans:beans&gt;</pre><ul><li>persistence.xml <em>(src/main/config/META-INF/persistence.xml)</em></li></ul><pre class="brush: xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"&gt;
  	&lt;persistence-unit name="monAppliPU" transaction-type="RESOURCE_LOCAL"&gt;
    	&lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;
    	&lt;non-jta-data-source&gt;jdbc/monAppliDS&lt;/non-jta-data-source&gt;
    	&lt;properties&gt;
      		&lt;property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/&gt;
      		&lt;property name="hibernate.hbm2ddl.auto" value="update"/&gt;
			&lt;property name="hibernate.show_sql" value="true"/&gt;
    	&lt;/properties&gt;
  	&lt;/persistence-unit&gt;
&lt;/persistence&gt;</pre><ul><li>context.xml <em>(src/main/webapp/META-INF/context.xml)</em></li></ul><pre class="brush: xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Context&gt;
	&lt;!-- Specify a JDBC datasource --&gt;
	&lt;ResourceLink name="jdbc/monAppliDS" global="jdbc/monAppliDS" type="javax.sql.DataSource"/&gt;
&lt;/Context&gt;</pre><ul><li>server.xml <em>(Servers/Tomcat v7.0 Server at localhost-config)</em></li></ul><pre class="brush: xml">&lt;GlobalNamingResources&gt;
    &lt;Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" name="jdbc/monAppliDS" password="XXXX" testOnBorrow="true" type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/patati_patata_db?autoReconnect=true" username="YYYY" validationQuery="SELECT 1"/&gt;
&lt;/GlobalNamingResources&gt;</pre>]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/configuration-de-base-dun-projet-spring-mvc-et-jpa-avec-annotations/feed</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>2 façons d&#8217;insérer les boutons de partage des réseaux sociaux twitter, facebook et google+</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/2-facons-dinserer-les-boutons-de-partage-des-reseaux-sociaux-twitter-facebook-et-google</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/2-facons-dinserer-les-boutons-de-partage-des-reseaux-sociaux-twitter-facebook-et-google#comments</comments> <pubDate>Sun, 04 Mar 2012 07:00:38 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[boutons]]></category> <category><![CDATA[facebook]]></category> <category><![CDATA[google]]></category> <category><![CDATA[réseaux sociaux]]></category> <category><![CDATA[twitter]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2714</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/2-facons-dinserer-les-boutons-de-partage-des-reseaux-sociaux-twitter-facebook-et-google"><img
align="left" hspace="5" width="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/03/boutons_reseaux_sociaux.jpg" class="alignleft wp-post-image tfe" alt="" title="boutons_reseaux_sociaux" /></a>Ajouter des boutons réseaux sociaux sur son site pour que vos pages soient partagées n&#8217;est plus quelque chose de difficile, il suffit de se rendre sur les sites concernés (twitter, facebook ou google+), de choisir son bouton et d&#8217;insérer le code généré dans vos pages. Ces bouts de code à insérer dans vos pages respectent [...]]]></description> <content:encoded><![CDATA[<p></p><p>Ajouter des boutons réseaux sociaux sur son site pour que vos pages soient partagées n&#8217;est plus quelque chose de difficile, il suffit de se rendre sur les sites concernés (twitter, facebook ou google+), de choisir son bouton et d&#8217;insérer le code généré dans vos pages.</p><p><img
class="aligncenter size-full wp-image-2715" title="boutons_reseaux_sociaux" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/03/boutons_reseaux_sociaux.jpg" alt="" width="189" height="120" /></p><p>Ces bouts de code à insérer dans vos pages respectent les deux principes suivants :</p><ol><li>ajout d&#8217;une zone html (lien ou calque) qui va servir à recevoir le bouton de partage</li><li>ajout d&#8217;un script javascript qui va permettre de construire le bouton et ses diverses options choisies</li></ol><h2>Ajout standard</h2><p>Cette solution standard permet d&#8217;obtenir tous les boutons proposés par les réseaux sociaux sur son propre site : grand, petit, vertical, horizontal, avec compteur, sans compteur, etc. Il suffit d&#8217;insérer quelques lignes de code et la magie opère au prochain chargement de votre site, vos boutons s&#8217;affichent à l&#8217;endroit où vous l&#8217;aurez choisi.</p><p>Cependant pour en arriver au résultat final, beaucoup de requêtes auront été faites et beaucoup de scripts auront été chargés, vous découvrirez ceci en détail dans la partie suivante &laquo;&nbsp;ajout simplifié&nbsp;&raquo;.</p><p>Voici les différents codes à insérer pour offrir à vos utilisateurs la possibilité de partager sur les 3 réseaux sociaux twitter, facebook et google+ :</p><p><span
style="text-decoration: underline;">Twitter</span></p><pre class="brush: javascript">&lt;a href="https://twitter.com/share" class="twitter-share-button" data-url="http://magicsupremacy.fr" data-via="xMIMIEx" data-lang="fr"&gt;Tweeter&lt;/a&gt;
&lt;script&gt;!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");&lt;/script&gt;</pre><p><span
style="text-decoration: underline;">Facebook</span></p><pre class="brush: javascript">&lt;div id="fb-root"&gt;&lt;/div&gt;
&lt;script&gt;(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/fr_FR/all.js#xfbml=1&amp;appId=109609109136303";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));&lt;/script&gt;</pre><p><span
style="text-decoration: underline;">Google+</span></p><pre class="brush: javascript">&lt;!-- Placez cette balise là où vous souhaitez positionner le bouton +1. --&gt;
&lt;div class="g-plusone" data-size="medium" data-href="http://magicsupremacy.fr"&gt;&lt;/div&gt;
&lt;!-- Placez cet appel d'affichage à l'endroit approprié. --&gt;
&lt;script type="text/javascript"&gt;
  window.___gcfg = {lang: 'fr'};
  (function() {
    var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
    po.src = 'https://apis.google.com/js/plusone.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
  })();
&lt;/script&gt;</pre><h2>Ajout simplifié</h2><p>Contrairement à la première solution, cette solution présente l&#8217;énorme avantage de ne pas alourdir vos pages d&#8217;1 ko, les boutons de partage sur les 3 réseaux sociaux ne sont que des liens vers la page de partage du réseau social concerné qui a la responsabilité de charger les différents scripts et styles.</p><pre class="brush: html">&lt;a href="https://twitter.com/share?url=http://magicsupremacy.fr"&gt;&lt;img src="tweet.png" alt="tweet"/&gt;&lt;/a&gt;
&lt;a href="http://www.facebook.com/share.php?u=http://magicsupremacy.fr"&gt;&lt;img src="like.png" alt="like"/&gt;&lt;/a&gt;
&lt;a href="https://plusone.google.com/_/+1/confirm?hl=fr&amp;url=http://magicsupremacy.fr"&gt;&lt;img src="plusone.png" alt="plusone"/&gt;&lt;/a&gt;</pre><p>Vous l&#8217;aurez compris avec cette méthode nous déportons totalement le chargement des scripts des réseaux sociaux qui alourdissent le chargement de nos pages, comme en atteste ce screenshot pris à l&#8217;instant qui révèle que l&#8217;insertion des différents bouts de code présentés ci-dessus (ajout standard) génère beaucoup de requêtes (21 !) et autant de temps de chargement (plus d&#8217;1/2 secondes) :</p><p
style="text-align: center;"><img
class="aligncenter  wp-image-2717" title="requêtes des 3 boutons" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/03/21requests1.png" alt="" width="730" height="459" /></p><p>L&#8217;inconvénient de cette méthode est qu&#8217;il n&#8217;est pas possible de visualiser depuis son site le nombre de partage par le biais de tel ou tel réseau social. J&#8217;ai personnellement opté pour cette option depuis aujourd&#8217;hui sur mon site magic.</p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/2-facons-dinserer-les-boutons-de-partage-des-reseaux-sociaux-twitter-facebook-et-google/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Paypal : Ajout d&#8217;un lien au lieu d&#8217;un bouton</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/paypal-ajout-dun-lien-au-lieu-dun-bouton</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/paypal-ajout-dun-lien-au-lieu-dun-bouton#comments</comments> <pubDate>Thu, 23 Feb 2012 23:01:40 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[bouton]]></category> <category><![CDATA[jquery]]></category> <category><![CDATA[lien]]></category> <category><![CDATA[paypal]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2702</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/paypal-ajout-dun-lien-au-lieu-dun-bouton"><img
align="left" hspace="5" width="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/02/photo-paypal.jpg" class="alignleft wp-post-image tfe" alt="" title="photo-paypal" /></a>C&#8217;est en ajoutant récemment un bouton de paiement Paypal sur mon site magic que j&#8217;ai remarqué que l&#8217;assistant de création de boutons proposé par Paypal ne permettait finalement uniquement d&#8217;intégrer un bouton image sur son site et non pas un simple lien. Pour ma part j&#8217;ai regretté cette alternative, j&#8217;ai donc dû la trouver moi-même, vous préférez [...]]]></description> <content:encoded><![CDATA[<p></p><p>C&#8217;est en ajoutant récemment un bouton de paiement Paypal sur mon site magic que j&#8217;ai remarqué que l&#8217;assistant de création de boutons proposé par Paypal ne permettait finalement uniquement d&#8217;intégrer un bouton image sur son site et non pas un simple lien.</p><p><a
href="https://www.paypal.fr/fr"><img
class="aligncenter size-full wp-image-2706" title="photo-paypal" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/02/photo-paypal.jpg" alt="" width="260" height="100" /></a></p><p
style="text-align: center;"><p>Pour ma part j&#8217;ai regretté cette alternative, j&#8217;ai donc dû la trouver moi-même, vous préférez un bouton image ? copiez-collez le code généré par Paypal, vous souhaitez un simple lien discret ? utilisez l&#8217;alternative javascript proposé ci-dessous.</p><h2>Bouton image</h2><p>Je vais prendre l&#8217;exemple du bouton de paiement &laquo;&nbsp;Dons&nbsp;&raquo; mais le code généré par l&#8217;assistant Paypal est très ressemblant pour l&#8217;ensemble de ses boutons, à savoir &laquo;&nbsp;Panier&nbsp;&raquo;, &laquo;&nbsp;Acheter&nbsp;&raquo;, &laquo;&nbsp;Dons&nbsp;&raquo;, &laquo;&nbsp;Chèques-cadeaux&nbsp;&raquo; et &laquo;&nbsp;Abonnements&nbsp;&raquo;.</p><p>Voici le genre de code qu&#8217;il vous faudra copier-coller pour avoir un bouton image &laquo;&nbsp;Dons&nbsp;&raquo; sur votre site :</p><pre class="brush: html">&lt;form target="paypal" action="https://www.paypal.com/cgi-bin/webscr" method="post"&gt;
    &lt;input type="hidden" name="cmd" value="_s-xclick"&gt;
    &lt;input type="hidden" name="hosted_button_id" value="AABBCCDDEEFFGG"&gt;
    &lt;input type="image" src="https://www.paypalobjects.com/fr_FR/FR/i/btn/btn_cart_LG.gif" border="0" name="submit" alt="PayPal - la solution de paiement en ligne la plus simple et la plus sécurisée !"&gt;
    &lt;img alt="" border="0" src="https://www.paypalobjects.com/fr_FR/i/scr/pixel.gif" width="1" height="1"&gt;
&lt;/form&gt;</pre><p><img
class="aligncenter size-full wp-image-2705" title="bouton-paypal" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/02/bouton-paypal.png" alt="" width="128" height="77" /></p><h2>Lien texte</h2><p>Pour obtenir un lien &laquo;&nbsp;Dons&nbsp;&raquo;, il existe deux façons, j&#8217;utilise personnellement la seconde car elle permet de masquer intégralement l&#8217;identifiant unique du bouton enregistré au niveau du compte.</p><ul><li>Sans Javascript</li></ul><p>Cette façon est très simple et correspond finalement à ce que propose déjà Paypal au niveau de l&#8217;onglet &laquo;&nbsp;Email&nbsp;&raquo; une fois le bouton généré, je lui reproche simplement le fait que nous voyons l&#8217;identifiant privé du bouton qui apparaît en bas du navigateur lors du survol du lien avec la souris :</p><pre class="brush: html">&lt;a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=AABBCCDDEEFFGG" title="PayPal - la solution de paiement en ligne la plus simple et la plus sécurisée !"&gt;Dons&lt;/a&gt;</pre><ul><li>Avec Javascript</li></ul><p>Cette façon est invisible et inodore, nous obtenons un lien qui ne fait apparaître nul part l&#8217;identifiant du bouton et renvoi exactement au même point qu&#8217;un bouton image dont le code a été présenté ci-dessus. En effet nous générons en javascript le formulaire de l&#8217;image bouton et le soumettons dans le même temps pour se rendre sur la page Paypal, de façon transparente pour l&#8217;utilisateur.</p><p>Voici un exemple en utilisant la bibliothèque jQuery :</p><pre class="brush:html">&lt;a id="donate"&gt;Dons&lt;/a&gt;</pre><pre class="brush:javascript">$('#donate').bind('click', function() {
	var paypal_dons_form =
		"&lt;form action=\"https://www.paypal.com/cgi-bin/webscr\" method=\"post\"&gt;" +
			"&lt;input type=\"hidden\" name=\"cmd\" value=\"_s-xclick\"&gt;" +
			"&lt;input type=\"hidden\" name=\"hosted_button_id\" value=\"AABBCCDDEEFFGG\"&gt;" +
			"&lt;input type=\"image\" src=\"https://www.paypalobjects.com/fr_FR/FR/i/btn/btn_donate_SM.gif\" border=\"0\" name=\"submit\" alt=\"PayPal - la solution de paiement en ligne la plus simple et la plus sécurisée !\"&gt;" +
			"&lt;img alt=\"\" border=\"0\" src=\"https://www.paypalobjects.com/fr_FR/i/scr/pixel.gif\" width=\"1\" height=\"1\"&gt;" +
		"&lt;/form&gt;";
	// génère un formulaire virtuel à la volée pour soumettre puis le supprime
	$(paypal_dons_form).appendTo('body').submit().remove();
});</pre><p>Voici ce que cela donne pour de vrai, visible au niveau du bas de page : <a
href="http://magicsupremacy.fr">lien de dons sur magicsupremacy</a></p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/paypal-ajout-dun-lien-au-lieu-dun-bouton/feed</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Mettre en pause un carrousel au survol de la souris</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/mettre-en-pause-un-carrousel-au-survol-de-la-souris</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/mettre-en-pause-un-carrousel-au-survol-de-la-souris#comments</comments> <pubDate>Fri, 27 Jan 2012 08:30:22 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[carrousel]]></category> <category><![CDATA[javascript]]></category> <category><![CDATA[jquery]]></category> <category><![CDATA[pause]]></category> <category><![CDATA[survol souris]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2680</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/mettre-en-pause-un-carrousel-au-survol-de-la-souris"><img
align="left" hspace="5" width="155" height="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/01/Carrousel_large01-150x150.jpg" class="alignleft wp-post-image tfe" alt="" title="Carrousel" /></a>Il n&#8217;existe quasiment plus de site d&#8217;informations sans carrousel qui présente les actualités à la une, les billets sponsorisés ou des publicités. Vous l&#8217;aurez compris je ne vous parle pas du manège &#171;&#160;chevaux en bois&#160;&#187; ou du tapis roulant dans les aéroports, mais bien de l&#8217;élément IHM qui consiste à afficher une liste d&#8217;items défilants, [...]]]></description> <content:encoded><![CDATA[<p></p><p>Il n&#8217;existe quasiment plus de site d&#8217;informations sans carrousel qui présente les actualités à la une, les billets sponsorisés ou des publicités.</p><p>Vous l&#8217;aurez compris je ne vous parle pas du manège &laquo;&nbsp;chevaux en bois&nbsp;&raquo; ou du tapis roulant dans les aéroports, mais bien de l&#8217;élément IHM qui consiste à afficher une liste d&#8217;items défilants, souvent de manière circulaire à l&#8217;image du Flip 3D dans Windows Vista et Windows 7 (touche Win+Tab), ou du célèbre affichage des albums dans iTunes.</p><p
style="text-align: center;"><img
class="aligncenter  wp-image-2681" title="Carrousel" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2012/01/Carrousel_large01.jpg" alt="" width="210" height="213" /></p><p>Ce ne sont pas les scripts ou plugins javascript qui manquent pour en mettre un en place sur votre site perso ou votre blog, l&#8217;un de ceux que j&#8217;utilise est le plugin <a
href="http://caroufredsel.frebsite.nl/" target="_blank">jQuery.carouFredSel</a> qui a le mérite d&#8217;être complet et simple d&#8217;utilisation, le seul reproche que je lui ferai est son poids car il pèse tout de même 30 ko en version minifiée.</p><h2>Structure du carrousel</h2><p>L&#8217;avantage de ce carrousel réside dans le fait qu&#8217;il est tout à fait possible de faire défiler du contenu HTML quel qu&#8217;il soit, au lieu d&#8217;être obligé de faire défiler des images. Voici un exemple de structure HTML simple que j&#8217;utilise :</p><pre class="brush: html">&lt;div id="carouselWrapper"&gt;
	&lt;div id="carousel"&gt;
		&lt;div class="work"&gt;
			&lt;img src="/img/portfolio/magicsupremacy.jpg" alt="Magic Supremacy" width="450" height="350" /&gt;
			&lt;h3&gt;Magic Supremacy&lt;/h3&gt;
			&lt;p&gt;
				Entièrement réalisé, ce site communautaire pour les joueurs de Magic l'Assemblée propose une multitude d'outils de qualité
				devenus rapidement indispensables pour les joueurs quel que soit leur niveau. Voici quelques fonctionnalités intéressantes :
				un simulateur de drafts qui permet de jouer entre amis, un générateur de paquets scellés, la création et le partage de decks
				et un design fluide et unique. Un exemple à suivre !
			&lt;/p&gt;
			&lt;a href="http://magicsupremacy.fr" target="_blank" title="Magic Supremacy"&gt;Visiter le site »&lt;/a&gt;
		&lt;/div&gt;
		&lt;div class="work"&gt;
			&lt;img src="/img/portfolio/desgeeksetdeslettres.jpg" alt="Des Geeks et des lettres" width="450" height="350" /&gt;
			&lt;h3&gt;Des Geeks et des lettres&lt;/h3&gt;
			&lt;p&gt;
				Ce blog WordPress a été customisé par nos soins. Simple mais efficace, il est la preuve que le minimalisme dans le design
				peut entraîner l'addiction du lecteur : avec plus de 1000 visites uniques journalières, ce blog peut vous donner envie
				d'ouvrir votre boutique en ligne et d'attirer les internautes dans votre &lt;em&gt;agence web&lt;/em&gt;.
			&lt;/p&gt;
			&lt;a href="http://desgeeksetdeslettres.com/blog" target="_blank" title="Des Geeks et des lettres"&gt;Visiter le site »&lt;/a&gt;
		&lt;/div&gt;
		&lt;div class="work"&gt;
			&lt;img src="/img/portfolio/agencewebdesigner.jpg" alt="Agence Web-Designer" width="450" height="350" /&gt;
			&lt;h3&gt;Agence Web-Designer&lt;/h3&gt;
			&lt;p&gt;
				Il ne s'agit ni plus ni moins que du site que vous êtes en train de consulter. Il vous présente rapidement ce en quoi vous
				êtes en mesure de vous attendre en nous confiant la création de votre espace web. Pour toute demande élaborée, n'hésitez pas
				à nous contacter directement.
			&lt;/p&gt;
			&lt;a href="http://agence-web-designer.fr" target="_blank" title="Agence Web-Designer"&gt;Visiter le site »&lt;/a&gt;
		&lt;/div&gt;
	&lt;/div&gt;
	&lt;a id="prev" href="#" title="Précédent"&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;
	&lt;a id="next" href="#" title="Suivant"&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;</pre><h2>Déclenchement du défilement</h2><p>Le plugin carouFredSel possède un attribut qui permet de lancer le défilement automatiquement ainsi qu&#8217;un paramètre permettant de régler le temps d&#8217;affichage entre chaque diapo, à titre d&#8217;exemple voici ce que cela donnerait :</p><pre class="brush: javascript">$('#carousel').carouFredSel({
	scroll	: {
		duration	: 0,
		pauseDuration	: 5000
	},
	auto	: true
});</pre><p>Cependant pour faire ce que nous souhaitons, à savoir pouvoir mettre en pause et reprendre le défilement au survol de la souris sur une diapo, je n&#8217;utilise pas l&#8217;option de défilement automatique offert par le plugin, je déclenche moi-même le changement de diapo toutes les X secondes en appelant l&#8217;évènement <em>next</em> qui permet de passer à la diapo suivante.</p><p>Voici le script JavaScript :</p><pre class="brush: javascript">var timer = setInterval(function() {
		$("#carousel").trigger("next");
	}, 5000);</pre><h2>Arrêt/Reprise du défilement</h2><p>La variable <em>timer</em> représente désormais le moyen de simuler l&#8217;arrêt et la reprise de l&#8217;opération paramétrée à la fonction setInterval(), à savoir le déclenchement du passage à la diapo suivante. L&#8217;arrêt du processus se fait en appelant la méthode clearInterval() sur la variable <em>timer</em>.</p><p>Il vous suffit alors de programmer les endroits où vous souhaitez que votre souris agisse sur le défilement, dans mon cas je choisis la diapo tout entière mais cela pourrait être uniquement le titre ou l&#8217;image, et d&#8217;écrire ces quelques lignes JavaScript :</p><pre class="brush: javascript">$('#carousel .work').mouseenter(function() {
		clearInterval(timer);
	}).mouseleave(function() {
		clearInterval(timer);
		timer = setInterval(function () {
				$("#carousel").trigger("next");
			}, 5000);
	});</pre><p>Pour voir le mécanisme en action, je vous invite à visiter notre nouveau site à Greg et moi, et de survoler avec votre souris le carrousel présenté en page d&#8217;accueil :</p><p
style="text-align: center;"><a
title="Greg et Mimie se lancent !" href="http://agence-web-designer.fr"><img
class="aligncenter" src="http://agence-web-designer.fr/img/icon/logo.jpg" alt="Agence Web-Designer" width="225" height="60" /></a></p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/mettre-en-pause-un-carrousel-au-survol-de-la-souris/feed</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Soumission d&#8217;un formulaire au format JSON avec jQuery</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/soumission-dun-formulaire-au-format-json-avec-jquery</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/soumission-dun-formulaire-au-format-json-avec-jquery#comments</comments> <pubDate>Thu, 12 Jan 2012 08:00:49 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[formulaire]]></category> <category><![CDATA[jquery]]></category> <category><![CDATA[json]]></category> <category><![CDATA[json-lib]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2654</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/soumission-dun-formulaire-au-format-json-avec-jquery"><img
align="left" hspace="5" width="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/12/json-file.png" class="alignleft wp-post-image tfe" alt="" title="JSON" /></a>J&#8217;ai jusque là utilisé principalement le format de données JSON pour récupérer des informations d&#8217;un quelconque service métier ou d&#8217;une API, comme récupérer les données d&#8217;un joueur ou les caractéristiques d&#8217;une carte Magic par exemple. Cependant le format JSON se prête aussi bien à la récupération d&#8217;informations qu&#8217;à l&#8217;envoi de données, c&#8217;est sur cette deuxième [...]]]></description> <content:encoded><![CDATA[<p></p><p>J&#8217;ai jusque là utilisé principalement le format de données JSON pour récupérer des informations d&#8217;un quelconque service métier ou d&#8217;une API, comme récupérer les données d&#8217;un joueur ou les caractéristiques d&#8217;une carte Magic par exemple.</p><p><img
class="aligncenter size-full wp-image-2655" title="JSON" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/12/json-file.png" alt="" width="128" height="128" /></p><p>Cependant le format JSON se prête aussi bien à la récupération d&#8217;informations qu&#8217;à l&#8217;envoi de données, c&#8217;est sur cette deuxième option que porte la suite de ce billet.</p><h2>Formulaire de contact</h2><p>(Je vous renvoi à <a
title="Struts : comment renvoyer des données JSON en AJAX" href="http://desgeeksetdeslettres.com/blog/programmation-java/struts-comment-renvoyer-des-donnees-json-en-ajax">cet ancien article</a> pour ceux qui souhaiteraient connaître une façon de retourner des données au format JSON depuis un contrôleur Java.)</p><p>Pour mettre en application l&#8217;envoi de données JSON vers un contrôleur Java, partons du principe que nous avons un formulaire de contact et que les données saisies par l&#8217;utilisateur doivent faire l&#8217;objet d&#8217;une action de sauvegarde en base de données par exemple.<br
/> La structure du formulaire de contact est la même pour les deux cas présentés ci-dessous :</p><ul><li>HTML</li></ul><pre class="brush: html">&lt;form action="" id="formContact"&gt;
	&lt;label for="nom"&gt;Nom&lt;/label&gt;
	&lt;input type="text" id="nom"/&gt;&lt;br/&gt;
	&lt;label for="prenom"&gt;Prénom&lt;/label&gt;
	&lt;input type="text" id="prenom"/&gt;&lt;br/&gt;
	&lt;label for="age"&gt;Age&lt;/label&gt;
	&lt;input type="text" id="age"/&gt;&lt;br/&gt;
	&lt;input type="submit" value="Envoyer"/&gt;
&lt;/form&gt;</pre><h3 style="padding-left: 30px;">Envoi éparpillé</h3><p>L&#8217;envoi classique correspond à envoyer les données saisies par l&#8217;utilisateur de façon unitaire, chaque champ du formulaire correspondant à un paramètre de la requête HTTP. Pour une quantité très réduite de données à envoyer cela peut suffire, mais lorsque nous parlons de dizaine voire de centaine de données, vous vous rendrez vite compte que cela nécessite trop de travail.</p><ul><li>JS</li></ul><pre class="brush: javascript">&lt;script src="http://code.jquery.com/jquery-1.7.1.min.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript"&gt;
		$(document).ready(function() {
			$('#formContact').submit(function() {
				var contact = {
					nom : $('#nom').val(),
					prenom : $('#prenom').val(),
					age : $('#age').val()
				};
				$.ajax({
					type: 'POST',
					url: 'contact.do',
					data: contact,
					success: function() {
						alert("fin du traitement java");
					}
				});
				return false;
			});
		});
	&lt;/script&gt;</pre><ul><li>JAVA</li></ul><pre class="brush: java">// Récupère des données saisies par l'utilisateur
String nom = request.getParameter("nom");
String prenom = request.getParameter("prenom");
String age = request.getParameter("age");
// création de l'objet à persister en base
Contact contact = new Contact();
contact.setNom(nom);
contact.setPrenom(prenom);
contact.setAge(age);
// TODO : contrôles éventuels &amp;  insertion en base de données</pre><p>L&#8217;inconvénient de cette méthode est que les données soumises à l&#8217;aide de l&#8217;objet JavaScript &#8216;contact&#8217; ne sont pas automatiquement transformées vers un objet de classe &#8216;Contact&#8217; en Java, les paramètres sont à récupérer un à un, charge à nous de construire l&#8217;objet Java à la main &#8230; imaginez le travail avec des dizaines de paramètres dans tous les sens.</p><p>La deuxième méthode présentée ci-dessous permet de faciliter et d&#8217;optimiser tout ce travail.</p><h3 style="padding-left: 30px;">Envoi groupé</h3><p>Vous l&#8217;aurez compris, ce principe permet de convertir simplement l&#8217;objet JavaScript &#8216;contact&#8217; en objet Java de classe &#8216;Contact&#8217;, voici les outils que l&#8217;on devra utiliser pour réussir ceci :</p><p
style="padding-left: 30px;">- l&#8217;envoi des données, côté client, se fait à présent au format JSON à l&#8217;aide d&#8217;un script JavaScript nommé <a
title="json2.js" href="https://github.com/douglascrockford/JSON-js">json2.js</a><br
/> - les données reçues au format JSON, côté serveur, peuvent à présent être converties en objet Java en une ligne grâce à la librairie <a
title="Json-lib" href="http://json-lib.sourceforge.net">Json-lib</a></p><ul><li>JS</li></ul><pre class="brush: javascript">&lt;script src="http://code.jquery.com/jquery-1.7.1.min.js"&gt;&lt;/script&gt;
&lt;script src="js/json2.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript"&gt;
		$(document).ready(function() {
			$('#formContact').submit(function() {
				var contact = {
					nom : $('#nom').val(),
					prenom : $('#prenom').val(),
					age : $('#age').val()
				};
				$.ajax({
					type: 'POST',
					url: 'contact.do',
					data: 'contact=' + JSON.stringify(contact),
					success: function() {
						alert("fin du traitement java");
					}
				});
				return false;
			});
		});
	&lt;/script&gt;</pre><ul><li>JAVA</li></ul><pre class="brush: java">// Récupère des données saisies par l'utilisateur
String contactAsString = request.getParameter("contact");
// création de l'objet à persister en base
JSONObject jsonObject = JSONObject.fromObject(contactAsString);
Contact contact = (Contact) JSONObject.toBean(jsonObject, Contact.class);
// TODO : contrôles éventuels &amp; insertion en base de données</pre><p>L&#8217;exemple simpliste de ce billet ne permet pas de se rendre compte tout à fait des possibilités offertes par l&#8217;utilisation du format JSON, étant donné que nous avons pris pour exemple un formulaire avec 3 champs très simples, mais croyez-moi l&#8217;utilisation de ce format d&#8217;échange entre le client et le serveur (dans les deux sens) est une véritable bénédiction et se fait très facilement <img
src='http://desgeeksetdeslettres.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/soumission-dun-formulaire-au-format-json-avec-jquery/feed</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>JavaScript : Les bonnes pratiques</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/javascript-les-bonnes-pratiques</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/javascript-les-bonnes-pratiques#comments</comments> <pubDate>Mon, 12 Dec 2011 13:27:32 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[bonne pratique]]></category> <category><![CDATA[guide]]></category> <category><![CDATA[javascript]]></category> <category><![CDATA[language rules]]></category> <category><![CDATA[style rules]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2645</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/javascript-les-bonnes-pratiques"><img
align="left" hspace="5" width="155" height="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/12/WikiBookTitel_JavaScript-150x150.jpg" class="alignleft wp-post-image tfe" alt="" title="JavaScript Guide" /></a>Avant d&#8217;appréhender un nouveau langage de programmation, il est utile voire primordiale de se documenter en amont pour comprendre un peu les subtilités et les rouages techniques du langage. Du temps bien dépensé qui vous permettra de ne pas pondre du code douteux ou mal écrit, surtout lorsque ce langage est JavaScript. Ce n&#8217;est pas [...]]]></description> <content:encoded><![CDATA[<p></p><p>Avant d&#8217;appréhender un nouveau langage de programmation, il est utile voire primordiale de se documenter en amont pour comprendre un peu les subtilités et les rouages techniques du langage. Du temps bien dépensé qui vous permettra de ne pas pondre du code douteux ou mal écrit, surtout lorsque ce langage est JavaScript.</p><p
style="text-align: center;"><a
href="http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml"><img
class="aligncenter size-full wp-image-2646" title="JavaScript Guide" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/12/WikiBookTitel_JavaScript.jpg" alt="" width="240" height="180" /></a></p><p>Ce n&#8217;est pas moi qui vais vous donner les bonnes pratiques du langage JavaScript, mais Google. Je viens de tomber sur cette page très bien faite qui va vous permettre de démarrer de la meilleure des façons : <a
href="http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml">Google JavaScript Style Guide</a>.</p><p>Chaque thème abordé par le document propose un exemple et un lien vers une page qui approfondie la bonne pratique, voici les sujets traités par le document :</p><ul><li><strong>JavaScript Language Rules</strong></li></ul><ol><li>var</li><li>Constants</li><li>Semicolons</li><li>Nested functions</li><li>Function Declarations Within Blocks</li><li>Exceptions</li><li>Custom exceptions</li><li>Standards features</li><li>Wrapper objects for primitive types</li><li>Multi-level prototype hierarchies</li><li>Method definitions</li><li>Closures</li><li>eval()</li><li>with() {}</li><li>this</li><li>for-in loop</li><li>Associative Arrays</li><li>Multiline string literals</li><li>Array and Object literals</li><li>Modifying prototypes of builtin objects</li><li>Internet Explorer&#8217;s Conditional Comments</li></ol><ul><li><strong>JavaScript Style Rules</strong></li></ul><ol><li>Naming</li><li>Custom toString() methods</li><li>Deferred initialization</li><li>Explicit scope</li><li>Code formatting</li><li>Parentheses</li><li>Strings Visibility (private and protected fields)</li><li>JavaScript Types</li><li>Comments</li><li>Inner Classes and Enums</li><li>Compiling</li><li>Tips and Tricks</li></ol><div>Avez-vous vous même des bonnes pratiques ou des astuces à nous faire partager ?</div> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/javascript-les-bonnes-pratiques/feed</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Gravatar : Mise en place d&#8217;une Tag Library</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/gravatar-mise-en-place-dune-tag-library</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/gravatar-mise-en-place-dune-tag-library#comments</comments> <pubDate>Fri, 04 Nov 2011 13:37:02 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[avatar]]></category> <category><![CDATA[email]]></category> <category><![CDATA[gravatar]]></category> <category><![CDATA[image]]></category> <category><![CDATA[tag library]]></category> <category><![CDATA[taglib]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2629</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/gravatar-mise-en-place-dune-tag-library"><img
align="left" hspace="5" width="155" src="http://s.gravatar.com/images/logo.png" class="alignleft wp-post-image tfe" alt="" title="Gravatar logo" /></a>Dans &#171;&#160;Gravatar&#160;&#187; il y a le mot &#171;&#160;Avatar&#160;&#187;, en disant ça tout est dit, ce service propose à n&#8217;importe qui de lier une image à une adresse email, généralement une image de profil représentant la personne physique liée à une adresse email virtuelle (avatar). Lorsque cette adresse email sera utilisée dans un blog ou forum [...]]]></description> <content:encoded><![CDATA[<p></p><p>Dans &laquo;&nbsp;Gravatar&nbsp;&raquo; il y a le mot &laquo;&nbsp;Avatar&nbsp;&raquo;, en disant ça tout est dit, <a
title="Gravatar" href="http://fr.wikipedia.org/wiki/Gravatar">ce service</a> propose à n&#8217;importe qui de lier une image à une adresse email, généralement une image de profil représentant la personne physique liée à une adresse email virtuelle (avatar).</p><p>Lorsque cette adresse email sera utilisée dans un blog ou forum au moment de la saisie d&#8217;un commentaire par exemple (un plug-in Gravatar est disponible sur la plupart des moteurs de blog connus), l&#8217;image &laquo;&nbsp;gravatar&nbsp;&raquo; associée à cette adresse email sera affichée automatiquement à côté de ce commentaire.</p><p>Pratique non ? plus besoin d&#8217;avoir à gérer sur chaque blog ou forum son avatar, l&#8217;adresse email suffit à présent.</p><p
style="text-align: center;"><a
href="http://fr.gravatar.com/"><img
class="aligncenter" title="Gravatar logo" src="http://s.gravatar.com/images/logo.png" alt="" width="274" height="55" /></a></p><p>J&#8217;ai voulu utiliser ce mécanisme sur mon site perso sur Magic l&#8217;Assemblée, au niveau des commentaires de cartes et de decks, c&#8217;est à présent chose faite (<a
href="http://magicsupremacy.fr/index.jsp#!menu=deck&amp;id=415">voici un exemple</a> en dépliant le bloc &laquo;&nbsp;Commentaires&nbsp;&raquo; en bas), et voici ce que j&#8217;ai du faire pour en arriver à ce résultat.</p><h2>Comment ça marche ?</h2><p>Le mécanisme mis en place par gravatar pour afficher une image à partir d&#8217;une adresse email est simple, il suffit d&#8217;utiliser la balise HTML &lt;img/&gt; et d&#8217;y mettre en attribut &laquo;&nbsp;src&nbsp;&raquo; une url gravatar avec l&#8217;adresse email concernée, cela pourrait se traduire de la façon suivante :</p><pre class="brush: html">&lt;img src="http://www.gravatar.com/avatar/monadresseemail@gmail.com"&gt;</pre><p>Toutefois, pour éviter le spam, les adresses e-mail sont hachées avec la fonction de <a
href="http://fr.wikipedia.org/wiki/Md5">cryptage MD5</a>. Cela empêche les robots de récupérer les adresses emails en clair dans le code source de la page.</p><p>Voici donc véritablement à quoi ressemble le code HTML qui permet d&#8217;afficher l&#8217;image gravatar liée à une adresse email.</p><pre class="brush: html">&lt;img src="http://www.gravatar.com/avatar/f628cd552adb34c7601d18bb0b94611f"&gt;</pre><p>Un avatar peut avoir des dimensions allant jusqu&#8217;à 512 pixels, il est toujours carré, et fait 80 pixels de côté par défaut. Si l&#8217;email n&#8217;est associé à aucun compte gravatar, une image par défaut apparaîtra.</p><p><img
class="aligncenter size-full wp-image-2630" title="Exemples image gravatar" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/11/gravatar_image.png" alt="" width="700" height="242" /></p><h2>Tag Library</h2><p>Les pages de mon site étant des JSP, c&#8217;est tout naturellement que je me suis penché du côté d&#8217;une taglib pour automatiser la génération du code présenté ci-dessus, cependant aucune taglib officielle n&#8217;existe.</p><p>Etant simple à écrire, voici le code qui m&#8217;a permis de réaliser cette &laquo;&nbsp;taglib gravatar maison&nbsp;&raquo; en s&#8217;inspirant de bouts de code par ci par là.</p><ul><li><span
style="text-decoration: underline;">Fichier de descripteur gravatar.tld</span></li></ul><pre class="brush: xml">&lt;?xml version="1.0" encoding="iso-8859-1" ?&gt;
&lt;!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
" http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"&gt;
&lt;taglib&gt;
	&lt;tlibversion&gt;1.0&lt;/tlibversion&gt;
	&lt;jspversion&gt;1.2&lt;/jspversion&gt;
	&lt;shortname&gt;Gravatar&lt;/shortname&gt;
	&lt;tag&gt;
		&lt;name&gt;image&lt;/name&gt;
		&lt;tagclass&gt;fr.mtg.supremacy.taglib.GravatarImageTag&lt;/tagclass&gt;
		&lt;bodycontent&gt;empty&lt;/bodycontent&gt;
		&lt;info&gt;Get avatar image from gravatar.com for the given email&lt;/info&gt;
		&lt;attribute&gt;
			&lt;name&gt;email&lt;/name&gt;
			&lt;required&gt;true&lt;/required&gt;
			&lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
		&lt;/attribute&gt;
		&lt;attribute&gt;
			&lt;name&gt;alt&lt;/name&gt;
			&lt;required&gt;false&lt;/required&gt;
			&lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
		&lt;/attribute&gt;
		&lt;attribute&gt;
			&lt;name&gt;size&lt;/name&gt;
			&lt;required&gt;false&lt;/required&gt;
			&lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
		&lt;/attribute&gt;
		&lt;attribute&gt;
			&lt;name&gt;className&lt;/name&gt;
			&lt;required&gt;false&lt;/required&gt;
			&lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
		&lt;/attribute&gt;
		&lt;attribute&gt;
			&lt;name&gt;defaultImage&lt;/name&gt;
			&lt;required&gt;false&lt;/required&gt;
			&lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
		&lt;/attribute&gt;
		&lt;attribute&gt;
			&lt;name&gt;rating&lt;/name&gt;
			&lt;required&gt;false&lt;/required&gt;
			&lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
		&lt;/attribute&gt;
	&lt;/tag&gt;
&lt;/taglib&gt;</pre><ul><li><span
style="text-decoration: underline;">Fichier web.xml</span></li></ul><pre class="brush: xml">...
&lt;jsp-config&gt;
	&lt;taglib&gt;
		&lt;taglib-uri&gt;gravatar.tld&lt;/taglib-uri&gt;
		&lt;taglib-location&gt;/WEB-INF/tld/gravatar.tld&lt;/taglib-location&gt;
	&lt;/taglib&gt;
&lt;/jsp-config&gt;
...</pre><ul><li><span
style="text-decoration: underline;">Classe fr.mtg.supremacy.taglib.GravatarImageTag</span></li></ul><pre class="brush: java">public class GravatarImageTag extends TagSupport {
	private static final long serialVersionUID = 2766493961169800616L;
	private static final String GRAVATAR_URL = "http://www.gravatar.com/avatar/";
	private String email;
	private String size = "80";
	private String rating = "g";
	private String defaultImage = "";
	private String alt = "";
	private String className = "";
	public void setEmail(Object email) {
		this.email = (String) email;
	}
	public void setSize(Object size) {
		this.size = (String) size;
	}
	public void setRating(Object rating) {
		this.rating = (String) rating;
	}
	public void setDefaultImage(String defaultImage) {
		this.defaultImage = defaultImage;
	}
	public void setAlt(Object alt) {
		this.alt = (String) alt;
	}
	public void setClassName(Object className) {
		this.className = (String) className;
	}
	/**
	 * create the img html tag
	 */
	@Override
	public int doStartTag() throws JspException {
		try {
			String hash = DigestUtils.md5Hex(email.toLowerCase());
			String avatar_url = GRAVATAR_URL + "" + hash;
			StringBuilder img = new StringBuilder("&lt;img src=\"");
			img.append(avatar_url);
			img.append("?size=" + size);
			img.append("&amp;d=" + defaultImage);
			img.append("&amp;r=" + rating + "\"");
			img.append(" alt=\"" + alt + "\"");
			img.append(" class=\"" + className + "\"");
			img.append("/&gt;");
			pageContext.getOut().print(img.toString());
		} catch (IOException e) {
			throw new JspException(e.getMessage());
		}
		return SKIP_BODY;
	}
}</pre><p>On notera au passage l&#8217;utilisation de la bibliothèque d&#8217;<a
href="http://commons.apache.org/codec/">Apache Commons Codec</a> (classe DigestUtils) qui nous permet en une ligne d&#8217;obtenir le hash MD5 de l&#8217;email.</p><ul><li><span
style="text-decoration: underline;">Utilisation dans une JSP</span></li></ul><pre class="brush: java">&lt;%@ taglib uri="gravatar.tld" prefix="gravatar" %&gt;
&lt;gravatar:profil email="mon.adresse.email@gmail.com"/&gt;</pre>]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/gravatar-mise-en-place-dune-tag-library/feed</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>SEO : Bien référencer son site Web full Ajax</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/seo-bien-referencer-son-site-web-full-ajax</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/seo-bien-referencer-son-site-web-full-ajax#comments</comments> <pubDate>Thu, 27 Oct 2011 07:52:19 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[SEO]]></category> <category><![CDATA[ajax]]></category> <category><![CDATA[google]]></category> <category><![CDATA[htmlunit]]></category> <category><![CDATA[java]]></category> <category><![CDATA[javascript]]></category> <category><![CDATA[référencement]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2558</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/seo-bien-referencer-son-site-web-full-ajax"><img
align="left" hspace="5" width="155" height="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/ajax-seo-150x150.jpg" class="alignleft wp-post-image tfe" alt="" title="AJAX &amp; SEO" /></a>AJAX Le gain d&#8217;un site Web full Ajax est clair d&#8217;après moi, tout le monde y gagne : le serveur : il est sollicité plus souvent mais ne retourne que des fragments de pages au lieu de l&#8217;intégralité du contenu des pages, souvent inutiles. Un gain de bande passante notable au passage le client : l&#8217;interface [...]]]></description> <content:encoded><![CDATA[<p></p><h2>AJAX</h2><p>Le gain d&#8217;un site Web full Ajax est clair d&#8217;après moi, tout le monde y gagne :</p><ul><li><strong>le serveur</strong> : il est sollicité plus souvent mais ne retourne que des fragments de pages au lieu de l&#8217;intégralité du contenu des pages, souvent inutiles. Un gain de bande passante notable au passage</li><li><strong>le client</strong> : l&#8217;interface est souvent plus fluide, les pages ne se rechargent pas entièrement à chaque clic et les actions nécessitant du temps ne bloquent pas l&#8217;utilisateur</li></ul><p>Ces points se vérifient si vous vous rendez sur mon site <a
href="http://magicsupremacy.fr">Magic l&#8217;Assemblée</a> qui est basé sur l&#8217;idée d&#8217;une application à page unique (<a
href="http://en.wikipedia.org/wiki/Single-page_application">Single-page application</a>).</p><p
style="text-align: center;"><a
href="http://fr.wikipedia.org/wiki/Seo"><img
class="size-full wp-image-2622 aligncenter" title="AJAX &amp; SEO" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/ajax-seo.jpg" alt="" width="236" height="236" /></a></p><h2>Méfiance</h2><p>L&#8217;AJAX (Asynchronous JavaScript And Xml) est pour beaucoup de personnes synonyme de mauvais référencement dans les moteurs de recherche, et elles n&#8217;ont pas tout à fait tort au premier abord même si le sujet de ce billet est justement de présenter des solutions de contournement (SEO).</p><p>Voici donc les deux principaux arguments contre une utilisation massive d&#8217;AJAX pour les sites web <span
style="text-decoration: underline;">Internet</span> &nbsp;&raquo;grand public&nbsp;&raquo; :</p><ol><li>les requêtes AJAX ne permettent pas de changer l&#8217;url de l&#8217;application, impossible donc d&#8217;utiliser l&#8217;historique de navigation des navigateurs et impossible de partager un lien vers le site pour qu&#8217;il affiche l&#8217;état sur lequel nous nous trouvons actuellement.</li><li>les robots d&#8217;indexation ne pouvant exécuter le JavaScript (langage du navigateur côté client) et les pages du site étant justement chargées par le biais de JavaScript (AJAX) signifie en effet que les robots (Googlebot, Bingbot, etc.) ne pourront pas indexer correctement les urls de vos pages &laquo;&nbsp;ajaxifiées&nbsp;&raquo;.</li></ol><p
style="text-align: center;"><a
href="http://fr.wikipedia.org/wiki/Robot_d'indexation"><img
class="aligncenter size-full wp-image-2623" title="Robots d'indexation ou Web crawler ou Web spider" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/web_spider.gif" alt="" width="300" height="191" /></a></p><h2>Contournement</h2><p>Le premier point soulevé dans les arguments contre est aujourd&#8217;hui assez facilement contournable mais reste néanmoins obligatoire à mettre en place pour résoudre le deuxième point sur le référencement des pages.</p><p>J&#8217;utilise personnellement une bibliothèque JavaScript, nommée <a
href="http://code.google.com/p/unfocus-history-keeper/">History Keeper</a>, qui me permet d&#8217;ajouter une ancre au niveau de l&#8217;url de l&#8217;application (#nom_ancre) et de mapper cette ancre vers une fonction JavaScript qui se chargera de lancer une requête AJAX vers le serveur. Cette bibliothèque me permet donc de changer l&#8217;état d&#8217;une page (ou de mon unique page) sans la recharger entièrement.</p><p
style="text-align: center;"><img
class="aligncenter size-full wp-image-2624" title="History navigation : back and next" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/back_next_history.gif" alt="" width="100" height="100" /></p><p>Chaque page possède désormais une url dédiée (<code>.../#page1</code>, <code>.../#page2</code>, etc.) qui rend l&#8217;historisation fonctionnelle au niveau du navigateur et permet le partage de liens vers un contenu spécifique.</p><p>A noter qu&#8217;il existe beaucoup d&#8217;autres solutions pour contourner ce premier point qui font qu&#8217;il n&#8217;en est plus vraiment un : jQuery propose <a
title="jQuery history" href="http://tkyk.github.com/jquery-history-plugin/">un plugin</a>, GWT propose <a
title="The GWT History Mechanism" href="http://code.google.com/intl/fr/webtoolkit/doc/latest/DevGuideCodingBasicsHistory.html">un mécanisme</a> en interne, Flex <a
title="Using the HistoryManager" href="http://livedocs.adobe.com/flex/3/html/help.html?content=deep_linking_8.html">en fait autant</a>, Vaadin <a
title="URI fragment &amp; history management" href="https://vaadin.com/book/-/page/advanced.urifu.html">aussi</a>, etc.</p><h2>Référencement</h2><p>Le second point évoqué dans les arguments contre est beaucoup plus complexe à appréhender et la solution proposée ci-dessous est plus délicate à mettre en place. En effet le nerf de la guerre reste le positionnement de son site dans les <a
title="SERP : search engine results page" href="http://fr.wikipedia.org/wiki/Page_de_r%C3%A9sultats_d%27un_moteur_de_recherche">SERPs</a> de Google principalement, un site mal référencé dans les moteurs de recherche est un site invisible ce qui entraîne donc peu de trafic, peu de backlinks, peu de ventes, peu de revenus publicitaires, etc.</p><p>Google a donc mis au point <a
title="Exploration AJAX : guide destiné aux webmasters et aux développeurs" href="http://www.google.com/support/webmasters/bin/answer.py?answer=174992">un mécanisme</a> destiné aux webmasters et aux développeurs qui va permettre à son robot de correctement indexer les urls AJAX d&#8217;un site, il n&#8217;y a plus qu&#8217;à comprendre ce qui est demandé et à le mettre en place.</p><p
style="text-align: center;"><img
class="aligncenter size-full wp-image-2626" title="Solution to make ajax applications crawlable" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/crawlerserver.png" alt="" width="708" height="356" /></p><ul><li><strong>Fragment de hachage</strong> (#! et _escaped_fragment_)</li></ul><p>Après résolution du premier point, nos URL AJAX présentent toutes à présent une ancre (ou fragment de hachage), tel que <code>www.example.com/index.html#mon_état</code>, où <code>#mon_état</code> correspond à l&#8217;ancre. Cependant le fragment de hachage est une particularité du navigateur et ne fait pas partie du protocole HTTP ce qui fait que ce paramètre n&#8217;est pas envoyé au serveur Web (Apache, Nginx, Lighttpd, etc.).</p><p>Ce qui implique que lorsque le robot va requêter des urls avec un #, l&#8217;état souhaité de la page ne pourra lui être retourné correctement, il faut donc que le robot interroge notre application sans fragment de hachage. C&#8217;est ce que propose Google en suffixant nos &laquo;&nbsp;ancres dynamiques&nbsp;&raquo; à l&#8217;aide du point d&#8217;exclamation (pour différencier les vraies &laquo;&nbsp;ancres statiques&nbsp;&raquo; des nouvelles) et en incluant dans son algorithme un mécanisme de transformation des urls contenant un tel paramètre (#!), sur le schéma &nbsp;&raquo;Pretty URL to Ugly URL&nbsp;&raquo; :</p><p><span
style="text-decoration: underline;">impact sur notre application</span></p><p><code>www.example.com/index.html#mont_état</code> devient alors <code>www.example.com/index.html#!mon_état</code></p><p><span
style="text-decoration: underline;">impact chez Googlebot</span></p><p><code>www.example.com/index.html#!mon_état</code> sera transformé en <code>www.example.com/index.html?_escaped_fragment_=mon_état</code></p><p>Cette fois-ci l&#8217;état de la page est envoyé au serveur Web, car le paramètre _escaped_fragment_ est un paramètre comme un autre autorisé dans le protocole HTTP. Il ne nous reste plus qu&#8217;à intercepter cette url dans notre application et de lui renvoyer le contenu de la page souhaitée (ça a l&#8217;air simple dit comme ça ? ^^).</p><ul><li><strong>Navigateur sans tête</strong> (servlet et htmlunit)</li></ul><p>Puisque les robots d&#8217;indexation ne peuvent exécuter de code JavaScript, il faut le faire à leur place, sous-entendu qu&#8217;il faut que notre serveur délivre un &laquo;&nbsp;snapshot&nbsp;&raquo; (un <em>instantané HTML)</em> de la page demandée lorsque le robot va requêter notre site. Ce snapshot doit correspondre à l&#8217;ensemble du contenu qui apparaît sur la page <span
style="text-decoration: underline;">après l&#8217;exécution du JavaScript</span>.</p><p
style="text-align: center;"><a
href="http://htmlunit.sourceforge.net/"><img
class="aligncenter size-full wp-image-2627" title="HtmlUnit - Headless Browser" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/htmlunit.gif" alt="" width="480" height="156" /></a></p><p>Pour cela nous avons donc besoin d&#8217;une servlet pour intercepter les url contenant _escaped_fragment_ et d&#8217;un headless browser qui va simuler pour nous le comportement du navigateur pour récupérer le contenu des pages demandées, l&#8217;outil HtmlUnit a été choisi pour réaliser cette tâche.</p><p>Google a mis à disposition un exemple de Servlet utilisée dans une démo GWT, le code est <a
href="http://code.google.com/p/google-web-toolkit/source/browse/branches/crawlability/samples/showcase/src/com/google/gwt/sample/showcase/server/CrawlServlet.java?spec=svn6231&amp;r=6231">accessible ici</a>. Voici cependant ma version qui inclut quelques nouveautés avec entre autre le moyen d&#8217;éviter que ces requêtes, appelées par les robots, ne soient prises en compte dans les statistiques de Google Analytics par exemple.</p><pre class="brush: java">/**
 * Servlet that makes this application crawlable
 */
public final class CrawlServlet implements Filter {
	private transient FilterConfig filterConfig = null;
	/**
	 * Initializes the filter configuration
	 */
	public void init(final FilterConfig filterConfig) {
		this.filterConfig = filterConfig;
	}
	/**
	 * Destroys the filter configuration
	 */
	public void destroy() {
		this.filterConfig = null;
	}
	/**
	 * Filters all requests and invokes headless browser if necessary
	 */
	@SuppressWarnings("unchecked")
	public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException {
		if (filterConfig == null) {
			return;
		}
		final HttpServletRequest req = (HttpServletRequest) request;
		final HttpServletResponse res = (HttpServletResponse) response;
		String queryString = req.getQueryString();
		if ((queryString != null) &amp;&amp; (queryString.contains("_escaped_fragment_"))) {
			final StringBuilder pageNameSb = new StringBuilder("http://");
			pageNameSb.append(req.getServerName());
			if (req.getServerPort() != 0) {
				pageNameSb.append(":");
				pageNameSb.append(req.getServerPort());
			}
			pageNameSb.append(req.getRequestURI());
			queryString = rewriteQueryString(queryString);
			pageNameSb.append(queryString);
			final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_3_6);
			new PinConnectionWrapper(webClient);
			webClient.setJavaScriptEnabled(true);
			webClient.setThrowExceptionOnScriptError(false);
			webClient.setAjaxController(new NicelyResynchronizingAjaxController());
			final String pageName = pageNameSb.toString();
			final HtmlPage page = webClient.getPage(pageName);
			res.setContentType("text/html;charset=UTF-8");
			final PrintWriter out = res.getWriter();
			out.println("&lt;hr&gt;");
			out.println("&lt;center&gt;&lt;h3&gt;You are viewing a non-interactive page that is intended for the crawler.  You probably want to see this page: &lt;a href=\""
					+ pageName + "\"&gt;" + pageName + "&lt;/a&gt;&lt;/h3&gt;&lt;/center&gt;");
			out.println("&lt;hr&gt;");
			out.println(page.asXml());
			webClient.closeAllWindows();
			out.close();
		} else {
			try {
				chain.doFilter(request, response);
			} catch (ServletException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * rewrite the URL back to the original #! version.
	 * remember to unescape any %XX characters.
	 * @param queryString
	 * @return
	 * @throws IOException
	 */
	private String rewriteQueryString(final String queryString) throws IOException {
		StringBuilder queryStringSb = new StringBuilder(queryString);
		int i = queryStringSb.indexOf("&amp;_escaped_fragment_");
		if (i != -1) {
			final StringBuilder tmpSb = new StringBuilder(queryStringSb.substring(0, i));
			tmpSb.append("#!");
			tmpSb.append(URLDecoder.decode(queryStringSb.substring(i + 20, queryStringSb.length()), "UTF-8"));
			queryStringSb = tmpSb;
		}
		i = queryStringSb.indexOf("_escaped_fragment_");
		if (i != -1) {
			final StringBuilder tmpSb = new StringBuilder(queryStringSb.substring(0, i));
			tmpSb.append("#!");
			tmpSb.append(URLDecoder.decode(queryStringSb.substring(i + 19, queryStringSb.length()), "UTF-8"));
			queryStringSb = tmpSb;
		}
		if (queryStringSb.indexOf("#!") != 0) {
			queryStringSb.insert(0, '?');
		}
		return queryStringSb.toString();
	}
	/**
	 * @author Mimie
	 *
	 */
	public class PinConnectionWrapper extends FalsifyingWebConnection {
	    public PinConnectionWrapper(final WebClient webClient) throws IllegalArgumentException {
	        super(webClient);
	    }
	    @Override
	    public WebResponse getResponse(final WebRequest request) throws IOException {
	        final WebResponse res = super.getResponse(request);
	        if (res.getWebRequest().getUrl().toExternalForm().endsWith(".css")
	        		|| res.getWebRequest().getUrl().toString().indexOf("plusone") != -1
	        		|| res.getWebRequest().getUrl().toString().indexOf("twitter") != -1
	        		|| res.getWebRequest().getUrl().toString().indexOf("facebook") != -1
	        		|| res.getWebRequest().getUrl().toString().indexOf("moderator") != -1
	        		|| res.getWebRequest().getUrl().toString().indexOf("google-analytics") != -1) {
	            return createWebResponse(res.getWebRequest(), "", "application/javascript", 200, "Ok");
	        }
	        return res;
	    }
	}
}</pre><p>Pour tester que tout fonctionne correctement, il vous suffit de tester une &laquo;&nbsp;Ugly URL&nbsp;&raquo; pointant sur une de vos pages pour voir le résultat, par exemple : <a
href="http://magicsupremacy.fr/index.jsp?_escaped_fragment_=menu=card&amp;submenu=advanced_search">http://magicsupremacy.fr/index.jsp?_escaped_fragment_=menu=card&amp;submenu=advanced_search</a>, ou sinon vous pouvez aussi le faire en vous connectant au site <a
href="https://www.google.com/webmasters/tools/home?hl=fr">Google Webmaster Tools</a>.</p><h2>A noter</h2><p>- Le robot n&#8217;indexe que le contenu des pages (le source HTML) et non la présentation, c&#8217;est pourquoi j&#8217;ai volontairement fait en sorte que les fichiers css ne soient pas téléchargés avec HtmlUnit.</p><p>- Pour vérifier que Googlebot a correctement indexé vos urls AJAX, il suffit de taper site:votre_nom_de_domaine dans le moteur de recherche pour voir le nombre de lien qu&#8217;il en ressort, par exemple : <a
href="http://www.google.fr/search?gcx=w&amp;sourceid=chrome&amp;ie=UTF-8&amp;q=site%3Amagicsupremacy.fr">site:magicsupremacy.fr</a> affiche 19400 résultats.</p><p>- Toutes les urls dans le code de votre application et celles de votre sitemap si vous en avez un, ne doivent contenir que les &laquo;&nbsp;Pretty URL&nbsp;&raquo; avec les #!, le paramètre _escaped_fragment_ ne doit jamais être présent.</p><p>- La bonne nouvelle est qu&#8217;il semblerait que ce mécanisme ait été repris par Bing dans une <a
href="http://www.bing.com/community/site_blogs/b/webmaster/archive/2011/06/08/updates-to-bing-webmaster-tools-data-and-content.aspx">mise à jour récente</a> de son Webmaster tools.</p><p
style="text-align: center;"><a
href="http://www.bing.com/toolbox/webmaster"><img
class="aligncenter size-full wp-image-2628" title="bing_#!" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/bing_.png" alt="" width="601" height="56" /></a></p><h2>Liens utiles</h2><p><a
href="http://code.google.com/intl/fr-FR/web/ajaxcrawling/">Making AJAX Applications Crawlable</a><br
/> <a
href="http://www.seomix.fr/referencement/naturel/ajax-headless-browser/">Le référencement de l&#8217;Ajax avec un Headless Browser</a><br
/> <a
href="http://www.webseoanalytics.com/blog/googles-ajax-crawling-scheme-and-its-effects-on-seo/">Google’s AJAX crawling scheme and its effects on SEO</a></p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/seo-bien-referencer-son-site-web-full-ajax/feed</wfw:commentRss> <slash:comments>11</slash:comments> </item> <item><title>Menu fixe mais flottant selon la scrollbar (JS + CSS)</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/menu-fixe-mais-flottant-selon-la-scrollbar-js-css</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/menu-fixe-mais-flottant-selon-la-scrollbar-js-css#comments</comments> <pubDate>Wed, 19 Oct 2011 14:15:16 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[css]]></category> <category><![CDATA[gmail]]></category> <category><![CDATA[javascript]]></category> <category><![CDATA[menu fixe]]></category> <category><![CDATA[menu flottant]]></category> <category><![CDATA[scrollbar]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2617</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/menu-fixe-mais-flottant-selon-la-scrollbar-js-css"><img
align="left" hspace="5" width="155" height="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/css_bloc2-150x150.jpg" class="alignleft wp-post-image tfe" alt="" title="Position relative/fixed" /></a>Certains ne comprennent peut-être pas ce dont je veux parler par &#171;&#160;menu fixe mais flottant selon la scrollbar&#160;&#187;, en fait je fais référence au nouveau menu dans Gmail qui est figé en haut mais suit la scrollbar lorsque nous descendons l&#8217;ascenseur. Cet effet permet d&#8217;avoir toujours à disposition le menu où que nous soyons dans [...]]]></description> <content:encoded><![CDATA[<p></p><p><img
class="aligncenter size-medium wp-image-2619" title="Position relative/fixed" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/css_bloc2-300x206.jpg" alt="" width="210" height="144" /><br
/> Certains ne comprennent peut-être pas ce dont je veux parler par &laquo;&nbsp;menu fixe mais flottant selon la scrollbar&nbsp;&raquo;, en fait je fais référence au nouveau menu dans Gmail qui est figé en haut mais suit la scrollbar lorsque nous descendons l&#8217;ascenseur.<br
/> Cet effet permet d&#8217;avoir toujours à disposition le menu où que nous soyons dans la lecture de nos mails.</p><p
style="text-align: center;"><img
class="aligncenter size-full wp-image-2618" title="Menu fixe-flottant Gmail" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/10/menu-fixe-gmail.png" alt="" width="697" height="31" /></p><p>Ça semble anodin au premier abord pour la plupart des gens, un peu de CSS, un petit &laquo;&nbsp;position: fixed&nbsp;&raquo; et le tour est joué ? hé bien non, c&#8217;est plus fort que ça, car au départ le menu est incrusté et c&#8217;est seulement lorque la scrollbar atteint un point précis (ici lorsque le haut de la fenêtre atteint le menu) que le menu devient flottant, c&#8217;est donc dynamique, à comprendre qu&#8217;il va falloir utiliser du JavaScript.</p><p>Ce menu m&#8217;a intrigué dès le départ car je ne savais pas moi-même réaliser un tel effet, jusqu&#8217;au jour où j&#8217;en ai eu besoin pour l&#8217;affichage d&#8217;un deck de type &laquo;&nbsp;Commander&nbsp;&raquo; sur <a
title="Magic Supremacy - Création et analyse de decks" href="http://magicsupremacy.fr">MS</a>.</p><h2>Démo</h2><p>En effet au niveau de la vue d&#8217;un deck, le survol de la souris sur le nom d&#8217;une carte fait afficher l&#8217;image de celle-ci sur le côté gauche. Le problème c&#8217;est que la quantité de cartes d&#8217;un deck &laquo;&nbsp;Commander&nbsp;&raquo; fait que l&#8217;image ne devient plus visible lorsque nous scrollons vers le bas pour voir l&#8217;intégralité des cartes. D&#8217;où l&#8217;idée de rendre flottante l&#8217;image de la carte lorsque la scrollbar tente de la masquer.</p><p>Pour vous rendre compte du résutlat obtenu, je vous invite à visiter cette page et à scroller vers le bas pour voir que l&#8217;image suit la scrollbar : <a
href="http://magicsupremacy.fr/#!/deck/id/598">Deck Magic l&#8217;Assemblée Momentary Rafiq EDH</a>.</p><h2>Code</h2><p>Finalement c&#8217;est assez simple à comprendre et donc à mettre en place.</p><ul><li>CSS</li></ul><p>Votre élément (menu, image, bandeau, div, etc.) a rendre flottant a par défaut une position &laquo;&nbsp;relative&nbsp;&raquo; par rapport à son conteneur, cette position devra passée à &laquo;&nbsp;fixed&nbsp;&raquo; au moment où nous le choisirons, dans notre cas lorsque la scrollbar tentera de masquer notre élément.</p><p>Le changement d&#8217;état de notre élement se fera par le biais d&#8217;une classe CSS, appliquée par du JavaScript, la voici :</p><pre class="brush: html">#votre_menu_ou_votre_image_ou_votre_element.floatable {
	position: fixed;
	top: 10px; // non-obligatoire
}</pre><ul><li>JS</li></ul><p>Pour détecter qu&#8217;il est temps de changer la position de notre élément, il faut connaître le positionnement de la scrollbar et la comparer au positionnement de notre élément. Pour cela j&#8217;utilise la fonction $(window).scroll() de jQuery.<br
/> Voici le mécanisme à mettre en place :</p><pre class="brush: javascript">// listen for scroll
var positionElementInPage = $('#votre_menu_ou_votre_image_ou_votre_element').offset().top;
$(window).scroll(
	function() {
		if ($(window).scrollTop() &gt;= positionElementInPage) {
			// fixed
			$('#votre_menu_ou_votre_image_ou_votre_element').addClass("floatable");
		} else {
			// relative
			$('#votre_menu_ou_votre_image_ou_votre_element').removeClass("floatable");
		}
	}
);</pre><p>Lorsque nous descendons l&#8217;image nous suit et reste visible, lorsque nous remontons, elle se recale à l&#8217;endroit du départ si nous dépassons son emplacement d&#8217;origine.</p><h2>Sources</h2><p>Si mes explications ne sont pas claires, voici un fichier d&#8217;exemple : <a
href="http://desgeeksetdeslettres.com/sources/menu_fixe_mais_flottant.html">menu_fixe_mais_flottant.html</a>.</p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/menu-fixe-mais-flottant-selon-la-scrollbar-js-css/feed</wfw:commentRss> <slash:comments>24</slash:comments> </item> <item><title>jRSS : Création de flux RSS en Java</title><link>http://desgeeksetdeslettres.com/blog/programmation-java/jrss-creation-de-flux-rss-en-java</link> <comments>http://desgeeksetdeslettres.com/blog/programmation-java/jrss-creation-de-flux-rss-en-java#comments</comments> <pubDate>Tue, 27 Sep 2011 15:37:48 +0000</pubDate> <dc:creator>Mimie</dc:creator> <category><![CDATA[Programmation]]></category> <category><![CDATA[flux]]></category> <category><![CDATA[generator]]></category> <category><![CDATA[java]]></category> <category><![CDATA[jrss]]></category> <category><![CDATA[rss]]></category> <category><![CDATA[xml]]></category> <guid
isPermaLink="false">http://desgeeksetdeslettres.com/blog/?p=2566</guid> <description><![CDATA[<a
href="http://desgeeksetdeslettres.com/blog/programmation-java/jrss-creation-de-flux-rss-en-java"><img
align="left" hspace="5" width="155" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/09/jrss.jpg" class="alignleft wp-post-image tfe" alt="" title="jrss" /></a>J&#8217;entends déjà de loin ceux qui pensent que créer son flux RSS à la main est chose facile (ce n&#8217;est que de l&#8217;XML) et qu&#8217;il n&#8217;est pas nécessaire d&#8217;utiliser une bibliothèque tierce pour réaliser cette tâche, je ne suis pas de cette avis et surtout lorsque la bibliothèque en question ne fait que 22 ko. [...]]]></description> <content:encoded><![CDATA[<p></p><p>J&#8217;entends déjà de loin ceux qui pensent que créer son flux RSS à la main est chose facile (ce n&#8217;est que de l&#8217;XML) et qu&#8217;il n&#8217;est pas nécessaire d&#8217;utiliser une bibliothèque tierce pour réaliser cette tâche, je ne suis pas de cette avis et surtout lorsque la bibliothèque en question ne fait que 22 ko.</p><p><a
href="http://jrss.sourceforge.net/"><img
class="aligncenter size-full wp-image-2594" title="jrss" src="http://desgeeksetdeslettres.com/blog/wp-content/uploads/2011/09/jrss.jpg" alt="" width="537" height="130" /></a></p><p><a
href="http://jrss.sourceforge.net/" rel="external">jRSS</a> m&#8217;a permis de me concentrer uniquement sur le contenu à mettre à disposition sans s&#8217;occuper des balises XML et autres fioritures englobant ce contenu, c&#8217;est exactement ce que je voulais.</p><h2>Ce que je souhaite</h2><p>Je souhaite présenter à mes abonnés les derniers tournois répertoriés sur mon site <a
href="http://magicsupremacy.fr">magicsupremacy.fr</a>, voici donc à quoi doit ressembler le flux RSS que je dois fournir (volontairement simplifié pour plus de clarté) :</p><pre class="brush: xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;rss version="2.0"&gt;
	&lt;channel&gt;
		&lt;title&gt;Les derniers Tournois ajoutés sur Magic Supremacy&lt;/title&gt;
		&lt;link&gt;http://magicsupremacy.fr/index.jsp#!menu=deck&amp;submenu=search_by_events&lt;/link&gt;
		&lt;description&gt;Une liste des derniers Tournois Magic l'Assemblée ajoutés, tout format confondu&lt;/description&gt;
		&lt;webMaster&gt;admin@magicsupremacy.fr&lt;/webMaster&gt;
		&lt;item&gt;
			&lt;title&gt;Magic Online Premier #2853353 - Pauper&lt;/title&gt;
			&lt;link&gt;http://magicsupremacy.fr/index.jsp#!menu=deck&amp;event=115&lt;/link&gt;
			&lt;description&gt;description simplifiée du tournoi #2853353&lt;/description&gt;
			&lt;author&gt;Admin&lt;/author&gt;
			&lt;pubDate&gt;sam., 24 sept. 2011 09:11:00 CEST&lt;/pubDate&gt;
		&lt;/item&gt;
		&lt;item&gt;
			&lt;title&gt;Magic Online Premier #2853358 - Standard 2010-2011 [ZEN M11 SOM]&lt;/title&gt;
			&lt;link&gt;http://magicsupremacy.fr/index.jsp#!menu=deck&amp;event=114&lt;/link&gt;
			&lt;description&gt;description simplifiée du tournoi #2853358&lt;/description&gt;
			&lt;author&gt;Admin&lt;/author&gt;
			&lt;pubDate&gt;dim., 25 sept. 2011 17:23:00 CEST&lt;/pubDate&gt;
		&lt;/item&gt;
	&lt;/channel&gt;
&lt;/rss&gt;</pre><p>Ce n&#8217;est pas forcément très complexe à réaliser seul, cependant l&#8217;utilisation de jRSS permet de donner un cadre de développement, une direction, en utilisant les objets adéquates, voici la façon dont j&#8217;ai procédé.</p><h2>Comment je m&#8217;y prends</h2><p>L&#8217;utilisation de jRSS permet soit de générer à la volée le flux RSS soit de générer le flux sous forme de fichier XML afin de le déposer dans un répertoire de l&#8217;application. J&#8217;ai opté pour la première solution, je ne stocke aucun fichier sur mon serveur.<br
/> Au lieu de manipuler des chaînes de caractères, jRSS permet de manipuler des objets Java, voici l&#8217;exemple qui permet de générer le flux présenté plus haut :</p><pre class="brush:java">final RSSFeedGenerator rssFeed = RSSFeedGeneratorFactory.getDefault();
final RSS rss = new RSS(RSS.VERSION_2_0);
final Channel channel = new Channel("Les derniers Tournois ajoutés sur Magic Supremacy", "http://magicsupremacy.fr/index.jsp#!menu=deck&amp;submenu=search_by_events", "Une liste des derniers Tournois Magic l'Assemblée ajoutés, tout format confondu");
channel.setWebMaster("admin@magicsupremacy.fr");
final Item item1 = new Item("Magic Online Premier #2853353 - Pauper", "http://magicsupremacy.fr/index.jsp#!menu=deck&amp;event=115", "description simplifiée du tournoi #2853353");
item1.setAuthor("Admin");
item1.setPubDate(new Date());
final Item item2 = new Item("Magic Online Premier #2853358 - Standard 2010-2011 [ZEN M11 SOM]", "http://magicsupremacy.fr/index.jsp#!menu=deck&amp;event=114", "description simplifiée du tournoi #2853358");
item2.setAuthor("Admin");
item2.setPubDate(new Date());
channel.addItem(item1);
channel.addItem(item2);
rss.addChannel(channel);
final String rssFeedGenerated = rssFeed.generateAsString(rss);</pre><p>La variable rssFeedGenerated représente le flux RSS souhaité. Il vous suffit ensuite de mettre à disposition de vos utilisateurs un lien ou un bouton pointant sur l&#8217;action qui appelle ce bout de code.</p><h2>Google Feedburner</h2><p>Pour masquer l&#8217;url de mon flux RSS un peu verbeuse à mes utilisateurs et surtout pour avoir des statistiques sur mes abonnés, j&#8217;utilise <a
href="http://feedburner.google.com" rel="external">Google Feedburner</a> qui me permet alors d&#8217;offrir une url &laquo;&nbsp;propre&nbsp;&raquo; à mes utilisateurs, celle-ci pointera ensuite sur la véritable url de l&#8217;application sans que cela se voit.</p><p>URL de l&#8217;action qui génère le flux RSS :</p><pre class="brush: html">http://magicsupremacy.fr/rss.do?action=getLatestEventsInFrench</pre><p>URL présentée aux utilisateurs grâce à Feedburner :</p><pre class="brush: html">http://feeds.feedburner.com/latest_events_magic_supremacy_fr</pre><p>Feedburner se charge au passage d&#8217;enregistrer le trafic au niveau de mes RSS et de me les présenter sous forme graphique, ça ne vaut pas le coup de s&#8217;en priver.</p> ]]></content:encoded> <wfw:commentRss>http://desgeeksetdeslettres.com/blog/programmation-java/jrss-creation-de-flux-rss-en-java/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> </channel> </rss>
