tag:blogger.com,1999:blog-52128874498042289312024-03-19T09:02:05.485-04:00GeekOnSpaceTecnología de la información, desarrollo de software, java, aplicaciones web.Unknownnoreply@blogger.comBlogger12125tag:blogger.com,1999:blog-5212887449804228931.post-79407859313230387382016-07-18T20:26:00.004-04:002016-07-19T19:43:34.642-04:00Enviar documentos desde una aplicación web hacia la impresora sin pre visualización en el navegadorEn este post explicare como imprimir un documento PDF directamente desde una aplicación web evitando la pre visualización por defecto que realizan los navegadores web o evitando también la descarga por defecto del documento en la maquina cliente.<br />
<br />
Para llevar a cabo la solución, vamos a utilizar una implementación open source (<a href="https://tyrus.java.net/">Project Tyrus</a>) de la especificación<span style="background-color: white; color: #555555; font-family: "open sans" , "calibri" , "candara" , "arial" , sans-serif; font-size: 14px; line-height: 20px; text-align: justify;"> </span><a class="externalLink" href="http://java.net/projects/websocket-spec" style="background-color: white; color: #0088cc; font-family: 'Open Sans', Calibri, Candara, Arial, sans-serif; font-size: 14px; line-height: 20px; text-align: justify; text-decoration: none;">JSR 356 - Java API for WebSocket</a> para establecer la comunicación entre la aplicación web y el servidor que deberá estar ejecutándose en la maquina cliente y que recibirá mediante WebSocket el documento a imprimir y enviar este a la impresora. A continuación los pasos a realizar utilizando el IDE IntelliJ IDEA:<br />
<br />
<h2>
<b>PASO 1: Creación del proyecto Tyrus donde se definirá el WebSocket endpoint y el servidor</b></h2>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8zehIcTysNyW8E4GEvELlVyBdp3T5KxyTv6oHJUVTjy4FdKFCAZOdrY55pykHZ8NHSmUhAeluONBn4jPwKXKuvrKaZcK-g2Eb9Jm7HrF3sn4_drZkXFdWgdqgPx6padR9T2FG-qCO2mhd/s1600/estructura+basica+del+proyecto.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8zehIcTysNyW8E4GEvELlVyBdp3T5KxyTv6oHJUVTjy4FdKFCAZOdrY55pykHZ8NHSmUhAeluONBn4jPwKXKuvrKaZcK-g2Eb9Jm7HrF3sn4_drZkXFdWgdqgPx6padR9T2FG-qCO2mhd/s400/estructura+basica+del+proyecto.png" width="400" /></a></div>
<div>
<br /></div>
<div>
<br />
<h2>
<b>PASO 2: Agregar las dependencias maven necesarias para la creación de nuestro servidor Tyrus</b></h2>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiMaajXK8ufZsZB8mE8Qt2Ypo2dImPRZIsfQzwWdLbXiwqIAZVW8wjGlJSEdqpev1RfhqtAftxn8FAZr2ECSO5fAdfd5G3i9ajAJy3n4w68ssyQsb8wbehIJ41CAxJvp8IGX47FRgn-YFH/s1600/maven+dependencias.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiMaajXK8ufZsZB8mE8Qt2Ypo2dImPRZIsfQzwWdLbXiwqIAZVW8wjGlJSEdqpev1RfhqtAftxn8FAZr2ECSO5fAdfd5G3i9ajAJy3n4w68ssyQsb8wbehIJ41CAxJvp8IGX47FRgn-YFH/s400/maven+dependencias.png" width="400" /></a></div>
<br />
<pre class="
toolbar: false;
brush: xml;
gutter: false;" style="color: #515151; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; font-size: small;"> <dependencies>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-server</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly-server</artifactId>
<version>1.13</version>
</dependency>
</dependencies></pre>
<pre class="
toolbar: false;
brush: java;
gutter: false;" style="color: #515151; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; font-size: small;"></pre>
<pre class="
toolbar: false;
brush: xml;
gutter: false;" style="color: #515151; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; font-size: small;"></pre>
<b></b><br />
<h2>
<b>PASO 3: Implementación del endpoint server FileServerEndpoint</b></h2>
</div>
<pre class="brush: java;">package ws.serverprinter.server;
import java.io.*;
import java.nio.ByteBuffer;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/receive/fileserver")
public class FileServerEndpoint {
static ByteArrayOutputStream baos = null;
@OnOpen
public void open(Session session, EndpointConfig conf) {
System.out.println("FileServerEndpoint is open");
}
@OnMessage
public void processUpload(ByteBuffer msg, boolean last, Session session) {
System.out.println("ByteBuffer message");
while(msg.hasRemaining()) {
baos.write(msg.get());
}
}
@OnMessage
public void message(Session session, String msg) {
System.out.println("Message: " + msg);
if(!msg.equals("end")) {
baos = new ByteArrayOutputStream();
}else {
try {
baos.flush();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnClose
public void close(Session session, CloseReason reason) {
System.out.println("WebSocket closed: "+ reason.getReasonPhrase());
}
@OnError
public void error(Session session, Throwable t) {
t.printStackTrace();
}
}
</pre>
<div style="font-family: consolas, 'bitstream vera sans mono', 'courier new', courier, monospace;">
<b></b><br />
<h2>
<b>PASO 4: Implementación de la aplicación principal y el server Tyrus</b></h2>
</div>
<div style="font-family: consolas, 'bitstream vera sans mono', 'courier new', courier, monospace;">
<pre class="brush: java;">package ws.serverprinter.server;
import org.glassfish.tyrus.server.Server;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* Created by williams on 19-07-16.
*/
public class MainApp {
public static void main(String[] args) {
runServer();
}
private static void runServer() {
Server server = new Server("localhost", 8025, "/websockets", null, FileServerEndpoint.class);
try {
server.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Press a key to stop the server.");
reader.readLine();
} catch (Exception e) {
e.printStackTrace();
} finally {
server.stop();
}
}
}
</pre>
</div>
<pre class="brush: xml;"></pre>
<b></b><br />
<h2>
<b>PASO 5: Desarrollo de la aplicación cliente</b></h2>
<br />
<pre class="brush: xml;"><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Chat</title>
</head>
<body>
<h2>File Upload</h2>
Select file
<input type="file" id="filename" />
<br>
<input type="button" value="Connect" onclick="connect()" />
<br>
<input type="button" value="Upload" onclick="sendFile()" />
<script>
var ws;
function connect() {
ws = new WebSocket("ws://localhost:8025/websockets/receive/fileserver");
ws.binaryType = "arraybuffer";
ws.onopen = function() {
alert("Connected.")
};
ws.onmessage = function(evt) {
alert(evt.msg);
};
ws.onclose = function() {
alert("Connection closed...");
};
ws.onerror = function(e) {
alert(e.msg);
}
}
function sendFile() {
var file = document.getElementById('filename').files[0];
ws.send('filename:'+file.name);
var reader = new FileReader();
var rawData = new ArrayBuffer();
reader.loadend = function() {}
reader.onload = function(e) {
rawData = e.target.result;
ws.send(rawData);
alert("file transferred.")
ws.send('end');
}
reader.readAsArrayBuffer(file);
}
</script>
</body>
</html></pre>
<b></b><br />
<h2>
<b>PASO 6: Implementación del servicio de impresión</b></h2>
<br />
<pre class="brush: java;"> @OnMessage
public void message(Session session, String msg) {
System.out.println("Message: " + msg);
if(!msg.equals("end")) {
baos = new ByteArrayOutputStream();
}else {
try {
baos.flush();
baos.close();
print(baos);
} catch (IOException e) {
e.printStackTrace();
} catch (PrintException e) {
e.printStackTrace();
}
}
}
private void print(ByteArrayOutputStream baos) throws PrintException {
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
if (services.length > 0) {
DocFlavor psInFormat = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc myDoc = new SimpleDoc(new ByteArrayInputStream(baos.toByteArray()), psInFormat, null);
DocPrintJob job = services[0].createPrintJob();
job.print(myDoc, null);
}
}
</pre>
<b></b><br />
<h2>
<b>PASO 7: Iniciamos el server Tyrus</b></h2>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiBvrQlfwM51TPkWptCyp492Ty-wLjt7PWjK4FMmwuocL8qor57gs2A2AFJjeVKKYzV29F9C9dQrK3TrpMPCcA7jNlVfDC-Y-BuxDUhQk4-yEC6eDzlb1z7LRYbknnNsTgVFODzITC5MyX/s1600/test+aplicacion.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiBvrQlfwM51TPkWptCyp492Ty-wLjt7PWjK4FMmwuocL8qor57gs2A2AFJjeVKKYzV29F9C9dQrK3TrpMPCcA7jNlVfDC-Y-BuxDUhQk4-yEC6eDzlb1z7LRYbknnNsTgVFODzITC5MyX/s400/test+aplicacion.png" width="400" /></a></div>
<h2>
<span style="font-family: "times new roman";"><span style="white-space: normal;"><b>PASO 8: Adjuntamos algún archivo PDF desde nuestra aplicación cliente y lo enviamos al server</b></span></span></h2>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdP-SkTM9HWFs56NMVNCORfmNePF7Eu-_9DS9S5A5R9peDUbu58kO3xHPVjiI0I9318EI5k2Xwaq6PIxVkRpZUNrZmgbORHJQ9ssDaBGMvdLXFqUnpavlB-YdTdOYf8F6YozK1a9rCj34w/s1600/file+transfered.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdP-SkTM9HWFs56NMVNCORfmNePF7Eu-_9DS9S5A5R9peDUbu58kO3xHPVjiI0I9318EI5k2Xwaq6PIxVkRpZUNrZmgbORHJQ9ssDaBGMvdLXFqUnpavlB-YdTdOYf8F6YozK1a9rCj34w/s1600/file+transfered.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOGkHLllPrfKOt5P6k6OtUQ5hyxWt62yxFTlED83rdJljlvFcWckljs_CGRj64E7Ly5fOcfeW3XMP9ff1gdpJj1Cx8RriNfSlSkz55Zqp8ZkyVhkbs_2Vr5bnj_z4gqSXEJrKHqqiBbNbS/s1600/impresora.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOGkHLllPrfKOt5P6k6OtUQ5hyxWt62yxFTlED83rdJljlvFcWckljs_CGRj64E7Ly5fOcfeW3XMP9ff1gdpJj1Cx8RriNfSlSkz55Zqp8ZkyVhkbs_2Vr5bnj_z4gqSXEJrKHqqiBbNbS/s1600/impresora.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5cbtP2A55uD5uQUECufLAqkaf119Dg320d3aSkc8pj2A8vwCUrU1g8aUb2eVFJv9ECl-qknTeK-lqD0VO8TMfTcfI-T5EqlDU9cVl_O0WzJMUbmzWgoo2VYiV0Q8ze_6T6qboGYua7ETO/s1600/log+server.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5cbtP2A55uD5uQUECufLAqkaf119Dg320d3aSkc8pj2A8vwCUrU1g8aUb2eVFJv9ECl-qknTeK-lqD0VO8TMfTcfI-T5EqlDU9cVl_O0WzJMUbmzWgoo2VYiV0Q8ze_6T6qboGYua7ETO/s1600/log+server.png" /></a></div>
<span style="font-family: "times new roman";"><span style="white-space: normal;"><br /></span></span>
<span style="font-family: "times new roman";"><span style="white-space: normal;">Se puede observar como el archivo se envió directamente a la impresora.</span></span><br />
<br />
<span style="font-family: "times new roman";"><span style="white-space: normal;">
</span></span>
<span style="font-family: "times new roman";"><span style="white-space: normal;">Fuentes:</span></span><br />
<span style="font-family: "times new roman";"><span style="white-space: normal;"><a href="https://tyrus.java.net/documentation/1.13/user-guide.html#standalone-mode">https://tyrus.java.net/documentation/1.13/user-guide.html#standalone-mode</a></span></span>
<span style="font-family: "times new roman";"><span style="white-space: normal;"><a href="http://stackoverflow.com/questions/21769470/file-upload-using-java-websocket-api-and-javascript">http://stackoverflow.com/questions/21769470/file-upload-using-java-websocket-api-and-javascript</a></span></span>
<span style="font-family: "times new roman";"><span style="white-space: normal;"><a href="http://docs.oracle.com/javase/7/docs/api/javax/print/package-summary.html">http://docs.oracle.com/javase/7/docs/api/javax/print/package-summary.html</a></span></span>
<span style="font-family: "times new roman";"><span style="white-space: normal;"><a href="https://java.net/projects/websocket-spec">https://java.net/projects/websocket-spec</a></span></span>
<br />
<span style="font-family: "times new roman";"><br /></span>
<span style="font-family: "times new roman";">Github: <a href="https://github.com/ghwrivas/server-printer-ws">https://github.com/ghwrivas/server-printer-ws</a></span><br />
<ol>
</ol>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-68173883827166453952014-06-10T15:31:00.000-04:302014-06-10T15:31:07.119-04:30Dynamic data binding spring web flowPojo:
<pre class="brush: java">
protected List<Integer> telefonos = new ArrayList<Integer>();
</pre>
Html:
<pre class="brush: html">
<c:forEach items="${telefonos}" var="telefono"
varStatus="status">
<input id="telefonos${status.index}" name="telefonos" type="text"
value="${telefono}" />
</c:forEach>
<input id="telefonosN" name="telefonos" type="text" value="" />
<input type="hidden" name="_telefonos" value="off" />
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-85040950332983670042014-04-09T11:36:00.001-04:302014-04-09T11:40:19.876-04:30Spring Web Flow - Prevenir el doble click cuando enviamos un formulario html pero sin dejar de enviar el botón presionadoEn la mayoría de aplicaciones muchas veces es necesario des-habilitar el botón tipo submit del un formulario html que se encarga de captura de datos para posteriormente persistir estos en la base de datos.<br />
<br />
En mi caso particular desarrollando una aplicación utilizando spring web flow, me fue necesario des-habilitar el botón que enviaba el formulario al servidor pero resulta que al des-habilitar el botón, este no es enviado con el formulario y para mi caso, spring web flow necesita saber el nombre del botón presionado para saber por donde continuar su flujo en el archivo de configuración del flujo.<br />
<br />
Extracto de mi archivo de configuración del flujo:<br />
<br />
<pre class="brush: xml"> <view-state id="form-datos-envio" model="guia" view="admin/guia/create/form-datos-envio">
<transition bind="false" on="cancel" to="end-state" validate="false">
<transition bind="false" on="back" to="form-add-item" validate="false">
<transition on="save" to="save-guia">
</transition></transition></transition></view-state>
<action-state id="save-guia">
<evaluate expression="guiaManager.saveGuia">
<transition on="success" to="view-saved-guia"></transition>
<transition on="error" to="form-datos-envio"></transition>
</evaluate></action-state>
<view-state id="view-saved-guia" view="admin/guia/create/view-saved-guia">
<transition bind="false" on="aceptar" to="end-state" validate="false">
</transition></view-state>
</pre>
<br />
Pueden observar que en el estado de la vista form-datos-envio, tenemos una transicion de nombre <b>save </b>la cual ejecutara la accion de guardar.<br />
<br />
Para hacer esto, create una funcion que valide el formulario al momento del submit y utilizare jquery en la vista conjuntamente con un input hidden en el cual guardare el nombre del botón presionado y así poder des-habilitar el botón pero enviar su nombre mediante un campo oculto.<br />
<br />
Botones necesarios en la vista:<br />
<br />
<pre class="brush: html"> <spring:message code="button_cancel" htmlescape="false" var="cancel">
<input id="cancel" name="cancel" type="submit" value="${fn:escapeXml(cancel)}" />
<spring:message code="button_back" htmlescape="false" var="back">
<input id="back" name="back" type="submit" value="${fn:escapeXml(back)}" />
<spring:message code="button_save" htmlescape="false" var="save">
<input id="save" name="save" type="submit" value="${fn:escapeXml(save)}" />
</spring:message></spring:message></spring:message></pre>
<br />
Campo oculto donde almacenare el valor del boton presionado:<br />
<br />
<pre class="brush: html"><input id="_eventId" name="_eventId" type="hidden" />
</pre>
<br />
Jquery:<br />
<br />
<pre class="brush: javascript"> <script type="text/javascript">
function validateOnSubmit(form) {
var button = $("#_eventId").val();
var valid = Spring.validateAll();
if (button != "save") {
return true;
} else {
if (!valid) {
return false;
} else {
if (confirm('Esta seguro de guardar los cambios realizados?')) {
$("#save").attr("disabled", "disabled");
return true;
} else {
return false;
}
}
}
}
/*Mediante esta funcion de jquery, todo elemento tipo submit que sea presionado se copiara su nombre al input de id: _eventId el cual no es mas que nuestro input hidden. Esta funcion se ejectura inmediatamente al presionar cualquier boton submit y justo antes de llamar a la funcion que valida el formulario al momento del envio*/
$(document).ready(function() {
$(":submit").click(function() {
$("#_eventId").val(this.name);
});
});
</script>
</pre>
<br />
Validacion del formulario en el evento onsubmit:<br />
<br />
<pre class="brush: html"> <form:form id="guia" method="POST" modelattribute="guia" onsubmit="return validateOnSubmit(this);">
</form:form></pre>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-88594025948125085652014-03-21T08:00:00.000-04:302014-03-21T08:00:07.111-04:30Autenticación LDAP Apache DebianUna mínima configuración para proteger el acceso al servidor apache2 en debian.<div>
<br /></div>
<div>
Contenido:</div>
<div>
<b>1-Configuracion del archivo httpd.conf</b></div>
<div>
Para los efectos de este blog, modificare el archivo httpd.conf. Para configuracion avanzadas, con host virtuales, deberan leer otro tipo de documentacion.</div>
<div>
Archivo httpd.conf:</div>
<div>
<pre style="white-space: pre-wrap; word-wrap: break-word;">LoadModule ldap_module /usr/lib/apache2/modules/mod_ldap.so
LoadModule authnz_ldap_module /usr/lib/apache2/modules/mod_authnz_ldap.so
<Directory /var/www>
AuthType Basic
AuthBasicProvider ldap
AuthzLDAPAuthoritative off
AuthName "Autenticacion con Active Directory"
AuthLDAPURL "ldap://mi.ip.com:389/ou=Unidad Organizativa,dc=dc1,dc=dc2?sAMAccountName?sub?(objectClass=*)"
AuthLDAPBindDN "cn=system,ou=SistemasAdministrativos,ou=Unidad Organizativa,dc=dc1,dc=dc2"
AuthLDAPBindPassword "systemPassword"
require valid-user
</Directory></pre>
<pre style="white-space: pre-wrap; word-wrap: break-word;">
</pre>
</div>
<div>
<b>2-Autenticación sobre el servidor</b></div>
<div>
Al intentar acceder al servidor se nos pedira nuestro usuario y password de active directory</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_61lbsZ83tAQEDZ_anMywV4eW5QOGarRnXn5vuoNf_b7lnp8jyVpw2riRgee4dpBE-hYgXwUFwwveUFl-VMR50HFFtYF9ZubtecE1D313twTgGLpAnNZ4ierFI5BiIJXPuWX5UdCROoQz/s1600/active-directory.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_61lbsZ83tAQEDZ_anMywV4eW5QOGarRnXn5vuoNf_b7lnp8jyVpw2riRgee4dpBE-hYgXwUFwwveUFl-VMR50HFFtYF9ZubtecE1D313twTgGLpAnNZ4ierFI5BiIJXPuWX5UdCROoQz/s1600/active-directory.jpg" height="120" width="320" /></a></div>
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-10330372778574477282014-03-13T15:58:00.001-04:302014-03-13T15:59:16.274-04:30Herramientas para desarrolladores: JsonView<div style="word-wrap: break-word;">
<span style="font-size: small;"><span style="background-color: white;"><b>JSONView for Chrome</b> valida texto en formato json. La validación se realiza usando implementacion javascript de JsonLint.</span></span></div>
<div style="word-wrap: break-word;">
<span style="font-weight: normal;"><span style="font-size: small;"><span style="background-color: white;"><br /></span></span></span><span style="font-size: small;"><span style="background-color: white;">El texto en formato json es extraído de la pagina que se esta desplegando en el navegador y visualizado de una manera como si se estuviera utilizando la etiqueta <pre> de html.</span></span></div>
<div style="word-wrap: break-word;">
<span style="font-weight: normal;"><span style="font-size: small;"><span style="background-color: white;"><br /></span></span></span><span style="font-family: 'Open Sans', arial, sans-serif; font-size: small; white-space: pre-wrap;"><span style="background-color: white; font-weight: normal;">Plugin para chronme: </span></span><span style="font-family: Open Sans, arial, sans-serif; font-size: small;"><span style="font-weight: normal; white-space: pre-wrap;"><a href="https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc">https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc</a></span></span></div>
<div style="word-wrap: break-word;">
<span style="font-family: Open Sans, arial, sans-serif; font-size: small;"><br /></span></div>
<div>
<span style="font-family: Open Sans, arial, sans-serif; font-size: small;">Ejemplo de la extensión en funcionamiento:</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSS2PQ3IUtzkuQSQP3bHCNf8L6m1QwY0ox62EWwDUUzMMZG0ODsKBskEugI_r3SMOznbmYWpdkyUqmvIjyq2hOIzZOBh0u61feAlXvr8_QJvLs9tjFeM7GwrqX3lC4zptbEJ8SUhm5xrng/s1600/test.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSS2PQ3IUtzkuQSQP3bHCNf8L6m1QwY0ox62EWwDUUzMMZG0ODsKBskEugI_r3SMOznbmYWpdkyUqmvIjyq2hOIzZOBh0u61feAlXvr8_QJvLs9tjFeM7GwrqX3lC4zptbEJ8SUhm5xrng/s1600/test.jpg" height="77" width="400" /></a></div>
<div>
<span style="font-family: Open Sans, arial, sans-serif; font-size: small;"><br /></span></div>
<div>
<span style="font-family: Open Sans, arial, sans-serif; font-size: small;"><br /></span></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-69270554489217374482014-03-13T10:29:00.004-04:302015-07-06T07:29:04.256-04:30Extracción de texto desde una imagen utilizando tesseract-ocr engineTesseract es probablemente el motor de OCR de fuente abierta más exacto disponible. En combinación con la Biblioteca de procesamiento Imagen Leptonica, puede leer una amplia variedad de formatos de imagen y los convierte a texto en más de 60 idiomas. Fue uno de los 3 mejores motores en el test de precisión de UNLV en 1995. Entre 1995 y 2006 tuvo poco trabajo hecho en él, pero desde entonces se ha mejorado ampliamente por Google. Es liberado bajo la licencia Apache 2.0.<br />
<br />
Fuente: <a href="https://github.com/tesseract-ocr/tesseract">https://github.com/tesseract-ocr/tesseract</a><br />
<br />
A continuación, mediante una simple aplicación consola de java les mostrare paso a paso como hacer uso de este poderoso motor.<br />
<br />
Contenido:<br />
<br />
<ol>
<li>Descargar la libreria.</li>
<li>Estructura del proyecto en eclipse</li>
<li>Escanear una imagen y definicion de la region a realizar la extraccion del texto.</li>
<li>Desarrollo de la aplicacion.</li>
<li>Ejecucion y verificacion de los resultados.</li>
</ol>
<div>
1. Descargar la libreria. Aquí: <a href="https://code.google.com/p/tesseract-ocr/downloads/list">https://code.google.com/p/tesseract-ocr/downloads/list</a></div>
<div>
<br /></div>
<div>
2. Estructura del proyecto en eclipse. Ver imagen a continuacion de como se debería ver tu proyecto.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz9Z2IM4lp8oY5y3Tr6BWXOQ3bUUaaoB99zxBYMo3Aflfwrth1Ul5F1J3Huj1INd9n4L-W8bneNWRq0DOyvZBxqaoBSPrfsQczstUcKgzxiouyO-wHTfuvnNNKFGAuwhELef5oHlGBth0g/s1600/estructura+del+proyecto.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz9Z2IM4lp8oY5y3Tr6BWXOQ3bUUaaoB99zxBYMo3Aflfwrth1Ul5F1J3Huj1INd9n4L-W8bneNWRq0DOyvZBxqaoBSPrfsQczstUcKgzxiouyO-wHTfuvnNNKFGAuwhELef5oHlGBth0g/s1600/estructura+del+proyecto.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
3. Para mi ejemplo he escaneado el documento de identidad en mi país y he definido manualmente la región de extracción donde se encuentra el numero identificador. La región encerrada con el recuadro rojo, es la región a obtener mediante el motor tesseract.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn3-d9clVKiDrFlbTMB4OBpjtnC64mWosXB-g7yUV5S2ejZWYWOvAQdZ0wug1Ngi8jqOWWvZ_F7vT3uSmyBlyZfstMKa2T6bXJDZnG2n8oW5fJB3iicGOJ0c52Aig-iOUb_WyZHmVUdwEP/s1600/williams.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn3-d9clVKiDrFlbTMB4OBpjtnC64mWosXB-g7yUV5S2ejZWYWOvAQdZ0wug1Ngi8jqOWWvZ_F7vT3uSmyBlyZfstMKa2T6bXJDZnG2n8oW5fJB3iicGOJ0c52Aig-iOUb_WyZHmVUdwEP/s1600/williams.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
4. Solo cree un archivo donde tengo un metodo principal y alli defino el lenguaje a utilizar, en mi caso español, creo un objeto Rectangle con las coordenadas de la región a realizar la extracción e imprimo por consola el texto procesado.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: java">public class TesseractUtil {
/**
* Region
*/
private static Rectangle DEFAULT_RECTANGLE_NUMERO_CEDULA_SIZE = new Rectangle(
340, 118, 300, 60);
private static String TYPE_DEFAULT_IMAGE = "jpg";
private static String DEFAULT_LANGUAJE = "spa";
public static void main(String[] args) throws IOException,
TesseractException {
File file = new File("C:\\Users\\usuario\\Pictures\\williams.jpg");
System.out.println("Identificador: " + getIdentificadorCedula(file));
}
public static String getIdentificadorCedula(File imageFile)
throws IOException, TesseractException {
Tesseract1 instance = new Tesseract1(); // JNA Direct Mapping
instance.setLanguage(DEFAULT_LANGUAJE);
BufferedImage image = bufferedImage(imageFile);
makeGray(image);
String result = instance.doOCR(image,
DEFAULT_RECTANGLE_NUMERO_CEDULA_SIZE);
result = cleanIdentificadorCedula(result);
return result;
}
public static BufferedImage bufferedImage(File file) throws IOException {
return ImageIO.read(file);
}
public static String cleanIdentificadorCedula(String identificadorCedula) {
String finalString = StringUtils.deleteWhitespace(identificadorCedula)
.trim().toUpperCase();
return finalString.replaceAll("[^\\d]", "");
}
public static BufferedImage cropImage(BufferedImage src, Rectangle rect) {
BufferedImage dest = src.getSubimage(rect.x, rect.y, rect.width,
rect.height);
return dest;
}
public static void saveImage(String outputFolder, String filename,
BufferedImage image, String type) throws IOException {
File folder = new File(outputFolder);
if (!folder.exists()) {
folder.mkdir();
}
folder = new File(outputFolder);
File save_path = new File(folder.getPath() + "\\" + filename + "."
+ TYPE_DEFAULT_IMAGE);
ImageIO.write(image, type, save_path);
}
public static void makeGray(BufferedImage img) {
for (int x = 0; x < img.getWidth(); ++x)
for (int y = 0; y < img.getHeight(); ++y) {
int rgb = img.getRGB(x, y);
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb & 0xFF);
int gray = (r + g + b) / 3;
img.setRGB(x, y, gray);
}
}
}
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
5. Salida por la consola: </div>
<div class="separator" style="clear: both; text-align: left;">
Identificador: 55555555</div>
<div>
<br /></div>
Unknownnoreply@blogger.com37tag:blogger.com,1999:blog-5212887449804228931.post-32447730396647283722014-03-12T15:58:00.001-04:302014-03-12T16:04:04.085-04:30Utilizando la API de JAVA.NET para leer data en formato JSON desde una URLJava.net permite realizar conexiones y transacciones a través de la red. Utilizando el paquete java.net podemos comunicar dos o más computadoras que estén en distintas partes del mundo.<br />
<br />
En nuestro código de ejemplo vamos a utilizar la clase HttpURLConnection la cual extiende de la clase URLConnection y da soporte especifico al protocolo HTTP.
<br />
<br />
Ejemplo:<br />
<br />
<pre class="brush: java">
public static String httpGet(String stringUrl) throws HttpGetException{
URL url;
try {
url = new URL(stringUrl);
} catch (MalformedURLException e2) {
throw new HttpGetException(e2.getCause());
}
HttpURLConnection urlConnection = null;
String dataJson = "";
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setConnectTimeout(5000); // set timeout to 5 seconds
BufferedReader in = new BufferedReader(new InputStreamReader(
urlConnection.getInputStream(), StandardCharsets.UTF_8));
StringBuffer sb = new StringBuffer();
String inputLine;
while ((inputLine = in.readLine()) != null) {
sb.append(inputLine);
}
dataJson = sb.toString();
} catch (java.net.SocketTimeoutException e) {
throw new HttpGetException(e);
} catch (IOException e) {
if (urlConnection instanceof HttpURLConnection) {
HttpURLConnection httpConn = (HttpURLConnection) urlConnection;
InputStream in = null;
try {
in = httpConn.getErrorStream();
StringBuffer buf = new StringBuffer();
byte[] cbuf = new byte[1024 * 64];
int r = in.read(cbuf);
while (r > -1) {
if (r > 0) {
buf.append(new String(cbuf, 0, r));
}
r = in.read(cbuf);
}
YoutubeJsonError jsonError = new YoutubeJsonError(
buf.toString());
throw new HttpGetException(jsonError.getMessage());
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return dataJson;
}
}
</pre>
Probando el método con la siguiente url:<br />
<a href="http://ip.jsontest.com/" style="background-color: #fbfaf7; border: 0px; color: #c30000; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 25.200000762939453px; margin: 0px; padding: 0px; text-decoration: none; vertical-align: baseline;">http://ip.jsontest.com/</a><br />
<br />
y con el metodo:<br />
<pre class="brush: java">
System.out.println(dataJson);
</pre>
<br />
<br />
Deberia mostrar el siguiente texto:<br />
<span class="p" style="border: 0px; font-family: inherit; font-size: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">{</span><span class="nt" style="border: 0px; color: navy; font-family: inherit; font-size: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">"ip"</span><span class="p" style="border: 0px; font-family: inherit; font-size: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">:</span><span style="background-color: #fdfefb; font-family: Monaco, 'Bitstream Vera Sans Mono', 'Lucida Console', Terminal, monospace; font-size: 14px; line-height: 25.200000762939453px;"> </span><span class="s2" style="border: 0px; color: #dd1144; font-family: inherit; font-size: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">"8.8.8.8"</span><span class="p" style="border: 0px; font-family: inherit; font-size: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">} donde los numeros ochos representaran la direccion de tu ip en la internet.</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-45616597664525302202014-03-11T08:56:00.002-04:302014-03-11T15:54:57.906-04:30YouTube API V3 + Spring RooEn este post voy a explicar cómo obtener los videos subidos a un canal youtube desde una aplicación web desarrollada con spring mvc. También explicare como obtener información relacionada al video: duración, cantidad de reproducciones… y como hacer un paginador del listado de videos.<br />
<br />
Para todo esto vamos a utilizar la api que nos provee google: YouTube Data API (v3). Esta api nos permite incorporar funcionalidades de youtube en nuestra propia aplicación. Se puede utilizar la api para buscar videos, insertar, actualizar y borrar recursos tales como videos o listas de reproducciones de video.<br />
<br />
Contenido:
<br />
<br />
<ol>
<li>Registrar nuestra aplicación para obtener una clave publica de google.</li>
<li>Definición del modelo para convertir la data json a objetos java.</li>
<li>Servicio spring que contendrá la api necesaria para la búsqueda de videos.</li>
<li>Definición del controlador que recibirá las peticiones realizadas por el usuario.</li>
<li>Diseño de la vista para mostrar la lista de videos de manera paginada.</li>
<li>Vista de la aplicación.</li>
</ol>
<div>
1. Registrar nuestra aplicación para obtener una clave publica de google.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhH04fQq00OGeTuNKZnVOl5yplBMQJlKWl5uKG8oDsZDu3UqefQdrhwz7079pCVMzlPyvr5_xfh-l3GOkAgHr39FpGhFc17lrpUvTzHc4KMXka0oqzVh1skZBhV777tPTOn8J_S1elfZvy/s1600/APIKEY.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhH04fQq00OGeTuNKZnVOl5yplBMQJlKWl5uKG8oDsZDu3UqefQdrhwz7079pCVMzlPyvr5_xfh-l3GOkAgHr39FpGhFc17lrpUvTzHc4KMXka0oqzVh1skZBhV777tPTOn8J_S1elfZvy/s1600/APIKEY.jpg" height="86" width="400" /></a></div>
<div>
<br /></div>
<div>
2. Definición del modelo para convertir la data json a objetos java: Vamos a crear dos clases java, una para manejar la información relacionada a la lista de videos retornada por google y otra clase para manejar la información del video.</div>
<pre class="brush: java">
public class VideoYoutube {
private String videoId;
private Date publischedAt;
private String channelId;
private String title;
private String description;
private String thumbnail;
private String channelTitle;
private String duration;
private Long viewCount;
public VideoYoutube() {
this.videoId = "";
this.publischedAt = null;
this.channelId = "";
this.title = "";
this.description = "";
this.thumbnail = "";
this.channelTitle = "";
this.duration = "";
this.viewCount = null;
}
public VideoYoutube(String videoId, Date publischedAt, String channelId,
String title, String description, String thumbnail,
String channelTitle, String duration, Long viewCount) {
super();
this.videoId = videoId;
this.publischedAt = publischedAt;
this.channelId = channelId;
this.title = title;
this.description = description;
this.thumbnail = thumbnail;
this.channelTitle = channelTitle;
this.duration = duration;
this.viewCount = viewCount;
}
public String getVideoId() {
return videoId;
}
public void setVideoId(String videoId) {
this.videoId = videoId;
}
public Date getPublischedAt() {
return publischedAt;
}
public void setPublischedAt(Date publischedAt) {
this.publischedAt = publischedAt;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getThumbnail() {
return thumbnail;
}
public void setThumbnail(String thumbnail) {
this.thumbnail = thumbnail;
}
public String getChannelTitle() {
return channelTitle;
}
public void setChannelTitle(String channelTitle) {
this.channelTitle = channelTitle;
}
public String getDuration() {
if (duration != null && !duration.equals("")) {
StringBuilder strPeriod = new StringBuilder();
PeriodFormatter formatter = ISOPeriodFormat.standard();
Period period = formatter.parsePeriod(duration);
if (period.getHours() > 0) {
strPeriod.append(period.getHours()).append(":");
}
if (period.getMinutes() < 10) {
strPeriod.append("0").append(period.getMinutes()).append(":");
} else {
strPeriod.append(period.getMinutes()).append(":");
}
if (period.getSeconds() < 10) {
strPeriod.append("0").append(period.getSeconds());
} else {
strPeriod.append(period.getSeconds());
}
return strPeriod.toString();
}
return duration;
}
public void setDuration(String duration) {
this.duration = duration;
}
public Long getViewCount() {
return viewCount;
}
public void setViewCount(Long viewCount) {
this.viewCount = viewCount;
}
}
public class PageResultYoutube {
private String nextPageToken;
private String prevPageToken;
private int totalResults;
private int resultsPerPage;
private Map<String, VideoYoutube> videosResults;
public PageResultYoutube(String nextPageToken, String prevPageToken,
int totalResults, int resultsPerPage,
Map<String, VideoYoutube> videosResults) {
super();
this.nextPageToken = nextPageToken;
this.prevPageToken = prevPageToken;
this.totalResults = totalResults;
this.resultsPerPage = resultsPerPage;
this.videosResults = videosResults;
}
public PageResultYoutube(String dataJson) {
JSONObject jo = new JSONObject(dataJson);
if (jo.has("nextPageToken")) {
nextPageToken = jo.getString("nextPageToken");
}
if (jo.has("prevPageToken")) {
prevPageToken = jo.getString("prevPageToken");
}
if (jo.has("pageInfo")) {
JSONObject pageInfo = jo.getJSONObject("pageInfo");
totalResults = pageInfo.getInt("totalResults");
resultsPerPage = pageInfo.getInt("resultsPerPage");
}
videosResults = new HashMap<String, VideoYoutube>();
if (jo.has("items")) {
JSONArray items = jo.getJSONArray("items");
VideoYoutube video;
for (int i = 0; i < items.length(); i++) {
video = new VideoYoutube();
JSONObject item = items.getJSONObject(i);
JSONObject id = item.getJSONObject("id");
JSONObject snippet = item.getJSONObject("snippet");
video.setVideoId(id.getString("videoId"));
video.setChannelId(snippet.getString("channelId"));
video.setChannelTitle(snippet.getString("channelTitle"));
video.setDescription(snippet.getString("description"));
video.setPublischedAt(new DateTime(snippet
.getString("publishedAt")).toDate());
video.setThumbnail(snippet.getJSONObject("thumbnails")
.getJSONObject("default").getString("url"));
video.setTitle(snippet.getString("title"));
videosResults.put(video.getVideoId(), video);
}
}
}
public String getVideoIdsSeparetedByComma() {
StringBuilder str = new StringBuilder();
if (videosResults != null && videosResults.size() > 0) {
for (Entry<String, VideoYoutube> entry : videosResults.entrySet()) {
str.append(entry.getKey()).append(",");
}
}// XXX fix validation
String finalStr = str.toString();
finalStr = finalStr.substring(0, finalStr.toString().length() - 1);
return finalStr;
}
public void addVideo(VideoYoutube video) {
videosResults.put(video.getVideoId(), video);
}
public String getNextPageToken() {
return nextPageToken;
}
public void setNextPageToken(String nextPageToken) {
this.nextPageToken = nextPageToken;
}
public String getPrevPageToken() {
return prevPageToken;
}
public void setPrevPageToken(String prevPageToken) {
this.prevPageToken = prevPageToken;
}
public int getTotalResults() {
return totalResults;
}
public void setTotalResults(int totalResults) {
this.totalResults = totalResults;
}
public int getResultsPerPage() {
return resultsPerPage;
}
public void setResultsPerPage(int resultsPerPage) {
this.resultsPerPage = resultsPerPage;
}
public Map<String, VideoYoutube> getVideosResults() {
return videosResults;
}
public void setVideosResults(Map<String, VideoYoutube> videosResults) {
this.videosResults = videosResults;
}
public void setContentDetailsVideos(String contentDetailsJson) {
JSONObject jo = new JSONObject(contentDetailsJson);
if (jo.has("items")) {
JSONArray items = jo.getJSONArray("items");
for (int i = 0; i < items.length(); i++) {
JSONObject item = items.getJSONObject(i);
VideoYoutube video = videosResults.get(item.get("id"));
JSONObject cd = item.getJSONObject("contentDetails");
video.setDuration(cd.getString("duration"));
JSONObject stats = item.getJSONObject("statistics");
video.setViewCount(stats.getLong("viewCount"));
videosResults.put(video.getVideoId(), video);
}
}
}
}
</pre>
<div>
<br /></div>
<div>
3. Servicio spring que contendrá la api necesaria para la búsqueda de videos.</div>
<pre class="brush: java">
/**
*
* @author Williams Rivas Created 20/02/2014 12:59:49
*
*/
@Service
public class YoutubeServiceImpl implements YoutubeService {
public static final String PARAM_MAX_RESULTS = "maxResults";
private static int DEFAULT_VALUE_MAX_RESULTS = 16;
private static String DEFAULT_VALUE_CHANNEL_ID = “XXXXXXXXXXXXXXXXXXXXXX";
public static final String PARAM_PART = "part";
public static final String DEFAULT_VALUE_PART = "snippet";
public static final String DEFAULT_VALUE_PARTS_VIDEOS = "contentDetails%2Cstatistics";
public static final String PARAM_PAGE_TOKEN = "pageToken";
public static final String PARAM_CHANNEL_ID = "channelId";
public static final String PARAM_VIDEO_IDS = "id";
public static final String PARAM_KEY = "key";
private static final String DEFAULT_VALUE_KEY = "API_KEY_GENERADA_EN_EL_PASO_UNO_DEL_CONTENIDO_DE_ESTE_POST";
public static final String URL_SEARCH_YOUTUBE = "https://www.googleapis.com/youtube/v3/search?type=video&";
public static final String URL_VIDEOS_LIST = "https://www.googleapis.com/youtube/v3/videos?";
public static final String PARAM_VALUE_SEPARATOR = "=";
public static final String PARAM_VALUE_CONCAT = "&";
public static final String PARAM_VALUE_COMMA = "%2C";
@Autowired
protected YoutubeCanalRepository youtubeCanalRepository;
@Override
public PageResultYoutube searchYoutubeVideos(String part, String channelId,
int maxResults, String pageToken) throws SearchYoutubeException {
setDefaultValues();
String query = buildQueryUrl(part, channelId, maxResults, pageToken,
null);
String dataJson = Util.httpGet(query);
PageResultYoutube page = new PageResultYoutube(dataJson);
String videoIds = page.getVideoIdsSeparetedByComma();
String contentDetailsJson = "";
try {
contentDetailsJson = Util.httpGet(buildQueryUrl(
DEFAULT_VALUE_PARTS_VIDEOS, null, DEFAULT_VALUE_MAX_RESULTS,
null, videoIds));
} catch (HttpGetException e) {
throw new SearchYoutubeException(e.getMessage());
}
page.setContentDetailsVideos(contentDetailsJson);
return page;
}
@Override
public PageResultYoutube searchYoutubeVideos(String part, String channelId,
int maxResults) throws SearchYoutubeException {
return searchYoutubeVideos(part, channelId, maxResults, null);
}
@Override
public PageResultYoutube searchYoutubeVideos()
throws SearchYoutubeException {
return searchYoutubeVideos(DEFAULT_VALUE_PART,
DEFAULT_VALUE_CHANNEL_ID, DEFAULT_VALUE_MAX_RESULTS);
}
private String buildQueryUrl(String part, String channelId, int maxResults,
String pageToken, String videoIds) {
StringBuilder url;
if (channelId != null && !channelId.equals("")) {
url = new StringBuilder(URL_SEARCH_YOUTUBE);
// parametro part
url.append(PARAM_PART).append(PARAM_VALUE_SEPARATOR);
if (part != null && !part.equals("")) {
if (!part.equals(DEFAULT_VALUE_PART)) {
url.append(DEFAULT_VALUE_PART);
} else {
url.append(part);
}
} else {
url.append(DEFAULT_VALUE_PART);
}
// parametro channel id
url.append(PARAM_VALUE_CONCAT).append(PARAM_CHANNEL_ID)
.append(PARAM_VALUE_SEPARATOR);
if (channelId != null && !channelId.equals("")) {
url.append(channelId);
} else {
url.append(DEFAULT_VALUE_CHANNEL_ID);
}
// pagina
if (pageToken != null && !pageToken.equals("")) {
url.append(PARAM_VALUE_CONCAT).append(PARAM_PAGE_TOKEN)
.append(PARAM_VALUE_SEPARATOR).append(pageToken);
}
} else { // busqueda no por canal sino por ids de videos
// https://www.googleapis.com/youtube/v3/videos?part=snippet%2CcontentDetails%2Cstatistics&id=uWKM4F2RAtI%2CJ2NIttHwZBA%2C6UliPT1LIc4%2CSaLWwDyHMvo&maxResults=3&key=AIzaSyBB8x12DXzrzXKhkum5f_Nv3Yl7-0GSwCg
url = new StringBuilder(URL_VIDEOS_LIST);
// parametro part
url.append(PARAM_PART).append(PARAM_VALUE_SEPARATOR);
if (part != null && !part.equals("")) {
if (!part.equals(DEFAULT_VALUE_PARTS_VIDEOS)) {
url.append(DEFAULT_VALUE_PARTS_VIDEOS);
} else {
url.append(part);
}
} else {
url.append(DEFAULT_VALUE_PARTS_VIDEOS);
}
// videos ids separados por comma
if (videoIds != null && !videoIds.equals("")) {
url.append(PARAM_VALUE_CONCAT).append(PARAM_VIDEO_IDS)
.append(PARAM_VALUE_SEPARATOR);
url.append(videoIds);
}
}
// max results
url.append(PARAM_VALUE_CONCAT).append(PARAM_MAX_RESULTS)
.append(PARAM_VALUE_SEPARATOR);
if (maxResults <= 0) {
url.append(DEFAULT_VALUE_MAX_RESULTS);
} else {
url.append(maxResults);
}
// key developer
url.append(PARAM_VALUE_CONCAT).append(PARAM_KEY)
.append(PARAM_VALUE_SEPARATOR).append(DEFAULT_VALUE_KEY);
return url.toString();
}
@Override
public PageResultYoutube searchYoutubeVideos(String pageToken)
throws SearchYoutubeException {
return searchYoutubeVideos(DEFAULT_VALUE_PART,
DEFAULT_VALUE_CHANNEL_ID, DEFAULT_VALUE_MAX_RESULTS, pageToken);
}
private void setDefaultValues() {
List<YoutubeCanal> canals = youtubeCanalRepository.findAll();
if (canals != null && canals.size() > 0) {
DEFAULT_VALUE_CHANNEL_ID = canals.get(0).getIdChannel();
DEFAULT_VALUE_MAX_RESULTS = canals.get(0).getMaxResults();
}
}
}
</pre>
<div>
<br /></div>
<div>
4. Definición del controlador que recibirá las peticiones realizadas por el usuario.</div>
<pre class="brush: java">
@RequestMapping("/youtube/**")
@Controller
public class YoutubeController extends GlobalModelAttributes {
@Autowired
private YoutubeService youtube;
@RequestMapping(method = RequestMethod.POST, value = "{id}")
public void post(@PathVariable Long id, ModelMap modelMap,
HttpServletRequest request, HttpServletResponse response) {
}
@RequestMapping
public String index(
@RequestParam(value = "page", required = false) String page,
ModelMap uiModel) {
PageResultYoutube result;
if (page != null) {
result = youtube.searchYoutubeVideos(page);
} else {
result = youtube.searchYoutubeVideos();
}
uiModel.addAttribute("youtube", result);
return "youtube/index";
}
}
</pre>
<div>
<br /></div>
<div>
5. Diseño de la vista para mostrar la lista de videos de manera paginada.</div>
<pre class="brush: xhtml">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:spring="http://www.springframework.org/tags"
xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0" class="not-panel">
<jsp:directive.page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"/>
<jsp:output omit-xml-declaration="yes" />
<h3>Videos Youtube</h3>
<div style="text-align: center;">
<c:if test="${not empty youtube.prevPageToken}">
<spring:url value="" var="previous">
<spring:param name="page" value="${youtube.prevPageToken}" />
</spring:url>
<spring:url value="/resources/images/resultset_previous.png" var="previous_image_url" />
<spring:message code="list_previous" var="previous_label" htmlEscape="false" />
<a class="image" href="${previous}" title="${fn:escapeXml(previous_label)}">
<img alt="${fn:escapeXml(previous_label)}" src="${previous_image_url}" />
</a>
</c:if>
<c:out value="${youtube.videosResults.size()}" /> <c:out value=" de "/><c:out value="${youtube.totalResults}" />
<c:if test="${not empty youtube.nextPageToken}">
<spring:url value="" var="next">
<spring:param name="page" value="${youtube.nextPageToken}" />
</spring:url>
<spring:url value="/resources/images/resultset_next.png" var="next_image_url" />
<spring:message code="list_next" var="next_label" htmlEscape="false" />
<a class="image" href="${next}" title="${fn:escapeXml(next_label)}">
<img alt="${fn:escapeXml(next_label)}" src="${next_image_url}" />
</a>
</c:if>
</div>
<div style="height: auto; display: inline-block;">
<c:forEach items="${youtube.videosResults}" var="entry">
<div class="gallery">
<a target="_blank" href="#"><img
src="${entry.value.thumbnail}" alt="${entry.value.title}" width="110"
height="90" /></a>
<div class="gallery-desc">${entry.value.title}</div>
<div class="gallery-desc">${entry.value.duration}</div>
<div class="gallery-desc">${entry.value.viewCount}<c:out value=" Reproducciones" ></c:out></div>
</div>
</c:forEach>
</div>
<br/>
<div style="text-align: center;">
<c:if test="${not empty youtube.prevPageToken}">
<spring:url value="" var="previous">
<spring:param name="page" value="${youtube.prevPageToken}" />
</spring:url>
<spring:url value="/resources/images/resultset_previous.png" var="previous_image_url" />
<spring:message code="list_previous" var="previous_label" htmlEscape="false" />
<a class="image" href="${previous}" title="${fn:escapeXml(previous_label)}">
<img alt="${fn:escapeXml(previous_label)}" src="${previous_image_url}" />
</a>
</c:if>
<c:out value="${youtube.videosResults.size()}" /> <c:out value=" de "/><c:out value="${youtube.totalResults}" />
<c:if test="${not empty youtube.nextPageToken}">
<spring:url value="" var="next">
<spring:param name="page" value="${youtube.nextPageToken}" />
</spring:url>
<spring:url value="/resources/images/resultset_next.png" var="next_image_url" />
<spring:message code="list_next" var="next_label" htmlEscape="false" />
<a class="image" href="${next}" title="${fn:escapeXml(next_label)}">
<img alt="${fn:escapeXml(next_label)}" src="${next_image_url}" />
</a>
</c:if>
</div>
</div>
</pre>
<div>
<br /></div>
<div>
6. Vista de la aplicación</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnRJesaZeo5ZBTS3CatLR3UrW8YO_TgpA-PHvH5m9AxiAYV6XqUZt1OGy2BhfURIwNWrsDLiHHa4L2k_EJv9adq4w5ae8sApwsnVFbdMorUvA2WB5p8u5L2WP_ZAazR7gGfmg6aVW1_ylm/s1600/printapp.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnRJesaZeo5ZBTS3CatLR3UrW8YO_TgpA-PHvH5m9AxiAYV6XqUZt1OGy2BhfURIwNWrsDLiHHa4L2k_EJv9adq4w5ae8sApwsnVFbdMorUvA2WB5p8u5L2WP_ZAazR7gGfmg6aVW1_ylm/s1600/printapp.jpg" height="380" width="400" /></a></div>
<div>
<br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-54178618629411005052013-06-14T10:20:00.000-04:302013-06-14T10:32:05.675-04:30Restringir usuarios mostrados en el widget "user suggestion" del manejador de contenido NuxeoUna manera de restringir los usuarios desplegados en el widget user suggestion de nuxeo, podría ser la siguiente:
<br/><br/>
<b>1-Sobreescribir el widget single_user_suggestion_widget_template.xhtml</b><br/><br/>
-En modo edicion del widget, crear otra variable llamada userGroup:
<pre class="brush: xhtml">
<c:set var="userGroup" value="#{nxu:test(!empty widgetProperty_userGroup, widgetProperty_userGroup, '')}" />
</pre>
El valor de esta variable se la pasaremos mediante custom properties del widget en nuxeo studio:
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg34Z60UHk8XQzUWAM268ioVJSxrJ5BJtqmQcSTOBSpqOLTuyy8Jsf0JSVT8RWrtP01tQ2bflJRPW07QxTBsOySwG-9ggFLVZ0iF_0jZS-9ruLAOiLuamtPC8sS2_nDik5AQmDwofjOX8Io/s1600/user+group+componet.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg34Z60UHk8XQzUWAM268ioVJSxrJ5BJtqmQcSTOBSpqOLTuyy8Jsf0JSVT8RWrtP01tQ2bflJRPW07QxTBsOySwG-9ggFLVZ0iF_0jZS-9ruLAOiLuamtPC8sS2_nDik5AQmDwofjOX8Io/s320/user+group+componet.jpg" /></a></div>
-Localizar el <i>rich:suggestionBox</i> component y realizar los siguientes cambios:
<pre class="brush: xhtml">
suggestionAction="#{myUserSuggestionActions.getSuggestions}"
</pre>
Agregar otro f:param
<pre class="brush: xhtml">
<f:param name="userSuggestionGroup" value="#{userGroup}" />
</pre>
Dentro de <pre class="brush: xhtml"><a4j:support event="onselect",..</a4j:support></pre> tambien agregar el f:param
<pre class="brush: xhtml">
<f:param name="userSuggestionGroup" value="#{userGroup}" />
</pre>
Dentro de <pre class="brush: xhtml"><nxu:valueHolder id="#{widget.id}_selectionOutput"... </nxu:valueHolder> </pre> agregar:
<pre class="brush: xhtml">
<nxu:set var="info" value="#{myUserSuggestionActions.getUserInfo(selectedValue)}" cache="true">
</pre>
<b>2-Sobre-escribir el método de busqueda localizado en el seam component UserSuggestionActions. Cree otra clase y nombre mi componente así: myUserSuggestionActions</b><br/><br/>
-Agregar estas variables a la clase:
<pre class="brush: java">
@RequestParameter
protected String userSuggestionGroup;
protected String cachedUserSuggestionGroup;
public static final String WILDCARD_ALL_USER_GROUP = "*.*";
</pre>
-Sobreescribir el método getUserSuggestions
<pre class="brush: java">
public List<DocumentModel> getUserSuggestions(Object input)
throws ClientException {
try {
String searchPattern = (String) input;
List<DocumentModel> users = new ArrayList<DocumentModel>();
if(searchPattern.trim().equals(WILDCARD_ALL_USER_GROUP)){
return getListUsersByWildCard();
}
users = userManager.searchUsers(searchPattern);
if (userSuggestionGroup != null && !userSuggestionGroup.equals("")) {
List<DocumentModel> usersByRol = new ArrayList<DocumentModel>();
DataModel dataModel = null;
for (DocumentModel doc : users) {
dataModel = doc.getDataModel(userConfig.schemaName);
NuxeoPrincipal principal = userManager
.getPrincipal((String) dataModel
.getValue(userConfig.nameKey));
if (principal != null
&& principal.isMemberOf(userSuggestionGroup)) {
usersByRol.add(doc);
}
}
return usersByRol;
} else {
return users;
}
} catch (SizeLimitExceededException e) {
addSearchOverflowMessage();
return Collections.emptyList();
} catch (Exception e) {
throw new ClientException("error searching for principals", e);
}
}
</pre>
-Agregar los otros métodos locales
<pre class="brush: java">
private List<DocumentModel> getListUsersByWildCard() throws ClientException{
List<DocumentModel> users = new ArrayList<DocumentModel>();
if (userSuggestionGroup != null && !userSuggestionGroup.equals("")) {
List<String> listUsernames = userManager.getUsersInGroup(userSuggestionGroup);
if(listUsernames!= null && listUsernames.size() >= 0){
for (String id : listUsernames) {
users.add(userManager.getUserModel(id));
}
}
}
return users;
}
</pre>
Si se utiliza un wildcard en conjunto con el nuevo parámetro del widget userGroup, entonces el widget mostrara todos los usuarios que pertenezcan al grupo pasado como parámetro. El wilcard utilizado es *.*
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-34779262928938359652013-03-13T16:37:00.001-04:302015-08-19T09:28:51.636-04:30Agregar nueva fila a una tabla utilizando jQueryAgregando una fila a una tabla utilizando la libreria jQuery.
<br />
<iframe width="100%" height="300" src="//jsfiddle.net/geekonspace/bb4aLm9e/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>Unknownnoreply@blogger.com15tag:blogger.com,1999:blog-5212887449804228931.post-86955720896888131742013-02-28T12:14:00.001-04:302013-03-01T10:04:51.521-04:30Restful spring roo - Spring Security - Cliente Jersey - En esta oportunidad voy a explicar cómo crear servicios restful en una aplicación generada mediante spring roo y desarrollaré una aplicación cliente jersey que lea la data expuesta en los servicios restful, no solamente leeré la data sino que demostraré como podemos editar un atributo y enviarlo de nuevo mediante un servicio rest con método <a href="http://www.w3.org/Protocols/HTTP/1.0/spec.html#PUT">PUT</a> para su actualización en la base de datos. También explicaré como configurar spring security de tal manera que para las urls que expongan los servicios rest queden aseguradas pero no redirijan a la página de login, dejando de esta manera la página de login para los otros módulos que estén asegurados. Voy a omitir los pasos de configuración de la base de datos y de ingeniería reversa de mis tablas. Solamente trabajaremos con una tabla llamada ejemplo la cual creó una entidad Ejemplo.java.<br />
<br />
A continuación los pasos a seguir y cumplir con los requerimientos expuestos:<br />
<br />
<span style="font-size: large;">1. Ejecutamos el comando json add:</span><br />
<b>json add --class ~.model.Ejemplo</b><br />
Este comando introducirá la anotación @RooJson en el tipo de destino especificado:<br />
<br />
<pre class="brush: java">@RooJson
public class Ejemplo {
}
</pre>
<br />
Y creara el siguiente archivo .aj donde están declarados todos los métodos que convertirán la entidad a json y viceversa:<br />
<pre class="brush: java">package org.springroo.model;
import flexjson.JSONDeserializer;
import flexjson.JSONSerializer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springroo.model.Ejemplo;
privileged aspect Ejemplo_Roo_Json {
public String Ejemplo.toJson() {
return new JSONSerializer().exclude("*.class").serialize(this);
}
public static Ejemplo Ejemplo.fromJsonToEjemplo(String json) {
return new JSONDeserializer<Ejemplo>().use(null, Ejemplo.class).deserialize(json);
}
public static String Ejemplo.toJsonArray(Collection<Ejemplo> collection) {
return new JSONSerializer().exclude("*.class").serialize(collection);
}
public static Collection<Ejemplo> Ejemplo.fromJsonArrayToEjemploes(String json) {
return new JSONDeserializer<List<Ejemplo>>().use(null, ArrayList.class).use("values", Ejemplo.class).deserialize(json);
}
}
</pre>
<br />
<span style="font-size: large;">2. Crear un controllador donde se expondrán los servicios rest mediante el siguiente comando: </span><br />
<b>controller class --class ~.web.EjemploController --preferredMapping /restAPI/ejemplo</b><br />
<br />
<br />
Esto creara la siguiente clase java:<br />
<br />
<pre class="brush: java">package org.springroo.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springroo.model.Ejemplo;
@RequestMapping("/restAPI/ejemplo")
@Controller
public class EjemploController {
}
</pre>
<br />
<span style="font-size: large;">3. Ejecutamos el comando web mvc json add: </span><br />
<b>web mvc json add --jsonObject ~.model.Ejemplo --class ~.web.EjemploController</b><br />
<br />
Este comando introduce la anotación @RooWebJson en el tipo de destino especificado.<br />
<br />
<pre class="brush: java">package org.springroo.web;
import org.springframework.roo.addon.web.mvc.controller.json.RooWebJson;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springroo.model.Ejemplo;
@RequestMapping("/restAPI/ejemplo")
@Controller
@RooWebJson(jsonObject = Ejemplo.class)
public class EjemploController {
}
</pre>
<br />
Creando este archivo .aj con los métodos crud restful:<br />
<br />
<pre class="brush: java">// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO.
// You may push code into the target .java compilation unit if you wish to edit any member(s).
package org.springroo.web;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springroo.model.Ejemplo;
import org.springroo.services.EjemploService;
import org.springroo.web.EjemploController;
privileged aspect EjemploController_Roo_Controller_Json {
@Autowired
EjemploService EjemploController.EjemploService;
@RequestMapping(value = "/{id}", headers = "Accept=application/json")
@ResponseBody
public ResponseEntity<string> EjemploController.showJson(@PathVariable("id") Integer id) {
Ejemplo Ejemplo = EjemploService.findEjemplo(id);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
if (Ejemplo == null) {
return new ResponseEntity<string>(headers, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<string>(Ejemplo.toJson(), headers, HttpStatus.OK);
}
@RequestMapping(headers = "Accept=application/json")
@ResponseBody
public ResponseEntity<string> EjemploController.listJson() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
List<ejemplo> result = EjemploService.findAllEjemploes();
return new ResponseEntity<string>(Ejemplo.toJsonArray(result), headers, HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.POST, headers = "Accept=application/json")
public ResponseEntity<string> EjemploController.createFromJson(@RequestBody String json) {
Ejemplo Ejemplo = Ejemplo.fromJsonToEjemplo(json);
EjemploService.saveEjemplo(Ejemplo);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
return new ResponseEntity<string>(headers, HttpStatus.CREATED);
}
@RequestMapping(value = "/jsonArray", method = RequestMethod.POST, headers = "Accept=application/json")
public ResponseEntity<string> EjemploController.createFromJsonArray(@RequestBody String json) {
for (Ejemplo Ejemplo: Ejemplo.fromJsonArrayToEjemploes(json)) {
EjemploService.saveEjemplo(Ejemplo);
}
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
return new ResponseEntity<string>(headers, HttpStatus.CREATED);
}
@RequestMapping(method = RequestMethod.PUT, headers = "Accept=application/json")
public ResponseEntity<string> EjemploController.updateFromJson(@RequestBody String json) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
Ejemplo Ejemplo = Ejemplo.fromJsonToEjemplo(json);
if (EjemploService.updateEjemplo(Ejemplo) == null) {
return new ResponseEntity<string>(headers, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<string>(headers, HttpStatus.OK);
}
@RequestMapping(value = "/jsonArray", method = RequestMethod.PUT, headers = "Accept=application/json")
public ResponseEntity<string> EjemploController.updateFromJsonArray(@RequestBody String json) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
for (Ejemplo Ejemplo: Ejemplo.fromJsonArrayToEjemploes(json)) {
if (EjemploService.updateEjemplo(Ejemplo) == null) {
return new ResponseEntity<string>(headers, HttpStatus.NOT_FOUND);
}
}
return new ResponseEntity<string>(headers, HttpStatus.OK);
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE, headers = "Accept=application/json")
public ResponseEntity<string> EjemploController.deleteFromJson(@PathVariable("id") Integer id) {
Ejemplo Ejemplo = EjemploService.findEjemplo(id);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
if (Ejemplo == null) {
return new ResponseEntity<string>(headers, HttpStatus.NOT_FOUND);
}
EjemploService.deleteEjemplo(Ejemplo);
return new ResponseEntity<string>(headers, HttpStatus.OK);
}
}
</string></string></string></string></string></string></string></string></string></string></string></string></string></string></ejemplo></string></string></string></string></pre>
<br />
<span style="font-size: large;">4. Asegurando nuestra aplicación mediante el siguiente comando:</span><br />
<b>spring security setup</b><br />
<br />
Este comando creara el siguiente archivo de configuración: applicationContext-security.xml<br />
<br />
Configuración que asegura nuestras urls de servicios rest pero sin redirigir a nuestro modulo de login:<br />
<!-- HTTP security configurations --><br />
<http pattern="/restAPI/**" create-session="stateless" authentication-manager-ref="authenticationManager"><br />
<intercept-url pattern="/restAPI/**" access="ROLE_ADMIN" /><br />
<http-basic /><br />
</http><br />
<br />
Y dejamos la configuración por defecto que nos genero spring roo:<br />
<br />
<http auto-config="true" use-expressions="true" create-session="always"><br />
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" /><br />
<logout logout-url="/resources/j_spring_security_logout" /><br />
<!-- Configure these elements to secure URIs in your application --><br />
<intercept-url pattern="/choices/**" access="hasRole('ROLE_ADMIN')" /><br />
<intercept-url pattern="/member/**" access="isAuthenticated()" /><br />
<intercept-url pattern="/resources/**" access="permitAll" /><br />
<intercept-url pattern="/**" access="permitAll" /><br />
</http><br />
<br />
<br />
<span style="font-size: large;">5. Probamos nuestras configuraciones en el navegador y la salida de nuestros servicios rest:</span><br />
<br />
Intentando acceder a un modulo seguro nos muestra el login form:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYEdBlVGAuFJL3Iw03EpuNDoT8UPC7z9bI-sk19sfWXajT_TEDmTx3AJbgs-9uFv9wQqZ4QiqXjZSzpu7ZrDU827RI7joxZt47AKeVPQ-tVBsAspJixNSAPljN-WCGT8q1SIweORWhlhpe/s1600/intentando+acceder+a+un+modulo+seguro+login+form.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYEdBlVGAuFJL3Iw03EpuNDoT8UPC7z9bI-sk19sfWXajT_TEDmTx3AJbgs-9uFv9wQqZ4QiqXjZSzpu7ZrDU827RI7joxZt47AKeVPQ-tVBsAspJixNSAPljN-WCGT8q1SIweORWhlhpe/s1600/intentando+acceder+a+un+modulo+seguro+login+form.jpg" height="138" width="320" /></a></div>
<br />
<br />
<img src="" /><br />
<br />
Intentado acceder a una url segura de nuestros servicios rest:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyHrRmzLsK9v-YQ1UyjE3dq-MhoewsIYH2a7QmAY5AokxTr2W_IaVepI_gwm87r0SCwfIfCbwtgc-ZQ6_IbfiTG9hxcyLk3q0J-NiCTro5ZXLZh6uR5W90CDXyj_i3uc3O7mJXkqz97JAl/s1600/intentado+acceder+a+una+url+rest.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyHrRmzLsK9v-YQ1UyjE3dq-MhoewsIYH2a7QmAY5AokxTr2W_IaVepI_gwm87r0SCwfIfCbwtgc-ZQ6_IbfiTG9hxcyLk3q0J-NiCTro5ZXLZh6uR5W90CDXyj_i3uc3O7mJXkqz97JAl/s1600/intentado+acceder+a+una+url+rest.jpg" height="146" width="320" /></a></div>
<br />
<br />
<img src="" /><br />
<br />
<br />
Consultando el registro con id = 1 de nuestra tabla ejemplo veamos la salida en nuestro navegador:<br />
url: http://localhost:8080/appXXXXXXX/restAPI/ejemplo/1 muestra la siguiente salida:<br />
<br />
{"id":1,"idejemplo":1,"t1":"","t11":"","t12":"","t13":"","t14":"","t15":"","t16":"","t17":"","t18":"","t2":"","t3":"","t4":"","t5":"","t6":"","t7":"","t8":"","text1":"WILLIAMS","text10":"","text11":"","text12":"","text13":"","text14":"","text15":"","text16":"","text17":"","text18":"","text19":"","text20":"","text21":"","text22":"","text23":"","text24":"","text25":"","text26":"","text27":"","text28":"","text29":"","text3":"","text30":"","text31":"","text32":"","text33":"","text34":"","text35":"","text36":"","text39":"","text4":"","text40":"","text41":"","text42":"","text43":"","text44":"","text45":"","text46":"","text47":"","text48":"","text49":null,"text5":"","text50":"","text52":"","text6":"","text7":"","text8":"","text9":""}<br />
<br />
Consultando todos los registros:<br />
url: http://localhost:8080/appNegocioIribarren/restAPI/ejemplo muestra la siguiente salida:<br />
<br />
[{"id":2,"idejemplo":2,"t1":null,"t11":null,"t12":null,"t13":null,"t14":null,"t15":null,"t16":null,"t17":null,"t18":null,"t2":null,"t3":null,"t4":null,"t5":null,"t6":null,"t7":null,"t8":null,"text1":null,"text10":null,"text11":null,"text12":null,"text13":null,"text14":null,"text15":null,"text16":null,"text17":null,"text18":null,"text19":null,"text20":null,"text21":null,"text22":null,"text23":null,"text24":null,"text25":null,"text26":null,"text27":null,"text28":null,"text29":null,"text3":null,"text30":null,"text31":null,"text32":null,"text33":null,"text34":null,"text35":null,"text36":null,"text39":null,"text4":null,"text40":null,"text41":null,"text42":null,"text43":null,"text44":null,"text45":null,"text46":null,"text47":null,"text48":null,"text49":null,"text5":null,"text50":null,"text52":null,"text6":null,"text7":null,"text8":null,"text9":null},{"id":3,"idejemplo":3,"t1":"","t11":"","t12":"","t13":"","t14":"","t15":"","t16":"","t17":"","t18":"","t2":"","t3":"","t4":"","t5":"","t6":"","t7":"","t8":"","text1":"","text10":"","text11":"","text12":"","text13":"","text14":"","text15":"","text16":"","text17":"","text18":"","text19":"","text20":"","text21":"","text22":"","text23":"","text24":"","text25":"","text26":"","text27":"","text28":"","text29":"","text3":null,"text30":"","text31":"","text32":"","text33":"","text34":"","text35":"","text36":"","text39":"","text4":"","text40":"","text41":"","text42":"","text43":"","text44":"","text45":"","text46":"","text47":null,"text48":"","text49":null,"text5":"","text50":"","text52":null,"text6":"","text7":"","text8":"","text9":""},{"id":1,"idejemplo":1,"t1":"","t11":"","t12":"","t13":"","t14":"","t15":"","t16":"","t17":"","t18":"","t2":"","t3":"","t4":"","t5":"","t6":"","t7":"","t8":"","text1":"WILLIAMS","text10":"","text11":"","text12":"","text13":"","text14":"","text15":"","text16":"","text17":"","text18":"","text19":"","text20":"","text21":"","text22":"","text23":"","text24":"","text25":"","text26":"","text27":"","text28":"","text29":"","text3":"","text30":"","text31":"","text32":"","text33":"","text34":"","text35":"","text36":"","text39":"","text4":"","text40":"","text41":"","text42":"","text43":"","text44":"","text45":"","text46":"","text47":"","text48":"","text49":null,"text5":"","text50":"","text52":"","text6":"","text7":"","text8":"","text9":""}]<br />
<br />
<span style="font-size: large;">6.Agreamos la siguiente dependencia en nuestro archivo pom.xml la necesitaremos para comenzar a desarrollar nuestra aplicación cliente:</span><br />
<br />
<dependency><br />
<groupId>com.sun.jersey</groupId><br />
<artifactId>jersey-client</artifactId><br />
<version>1.8</version><br />
</dependency><br />
<br />
<br />
<span style="font-size: large;">7. Creando nuestra aplicación cliente mediante la api de jersey client, la explicaré mediante el mismo código:</span><br />
<br />
<pre class="brush: java">package org.springroo.test;
import java.io.IOException;
import javax.naming.AuthenticationException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.star.lang.IllegalArgumentException;
public class ClientJersey {
public static void main(String[] args) throws IOException,
AuthenticationException {
Client client = Client.create();
try {
String auth = new sun.misc.BASE64Encoder().encode("admin:admin"
.getBytes());
WebResource webResource = client
.resource("http://192.168.1.103:8080/appXXXXXX/restAPI/ejemplo");
ClientResponse response = webResource
.header("Authorization", "Basic " + auth)
.type("application/json").accept("application/json")
.get(ClientResponse.class);
int statusCode = response.getStatus();
if (statusCode == 401) {
throw new AuthenticationException(
"Invalid Username or Password");
}
if (statusCode == 403) {
throw new AuthenticationException("Usuario no autorizado");
}
//Obtenemos el arreglo de objetos Ejemplo y lo recorremos para obtener el objeto de id = 1
JSONArray ja = new JSONArray(response.getEntity(String.class));
JSONObject joForUpdate = null;
for (int i = 0; i < ja.length(); i++) {
if (ja.getJSONObject(i).getInt("id") == 1) {
joForUpdate = ja.getJSONObject(i);
break;
}
}
if (joForUpdate == null)
throw new IllegalArgumentException("json object null");
System.out.println(joForUpdate.get("id"));
joForUpdate.put("text1", "RIVAS");
// Luego de obtener el objeto de id = 1 realizamos la actualizacion de su atributo text1
response = webResource.header("Authorization", "Basic " + auth)
.type("application/json").accept("application/json")
.put(ClientResponse.class, joForUpdate.toString());
System.out.println("Estatus: " + response.getStatus());
} catch (JSONException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} finally {
client.destroy();
}
}
}
</pre>
<br />
<span style="font-size: large;">8. Verificación de si el atributo text1 del registro con id = 1 cambio:</span><br />
url: http://localhost:8080/appXXXXXX/restAPI/ejemplo<br />
<br />
[{"id":2,"idejemplo":2,"t1":null,"t11":null,"t12":null,"t13":null,"t14":null,"t15":null,"t16":null,"t17":null,"t18":null,"t2":null,"t3":null,"t4":null,"t5":null,"t6":null,"t7":null,"t8":null,"text1":null,"text10":null,"text11":null,"text12":null,"text13":null,"text14":null,"text15":null,"text16":null,"text17":null,"text18":null,"text19":null,"text20":null,"text21":null,"text22":null,"text23":null,"text24":null,"text25":null,"text26":null,"text27":null,"text28":null,"text29":null,"text3":null,"text30":null,"text31":null,"text32":null,"text33":null,"text34":null,"text35":null,"text36":null,"text39":null,"text4":null,"text40":null,"text41":null,"text42":null,"text43":null,"text44":null,"text45":null,"text46":null,"text47":null,"text48":null,"text49":null,"text5":null,"text50":null,"text52":null,"text6":null,"text7":null,"text8":null,"text9":null},{"id":3,"idejemplo":3,"t1":"","t11":"","t12":"","t13":"","t14":"","t15":"","t16":"","t17":"","t18":"","t2":"","t3":"","t4":"","t5":"","t6":"","t7":"","t8":"","text1":null,"text10":"","text11":"","text12":"","text13":"","text14":"","text15":"","text16":"","text17":"","text18":"","text19":"","text20":"","text21":"","text22":"","text23":"","text24":"","text25":"","text26":"","text27":"","text28":"","text29":"","text3":null,"text30":"","text31":"","text32":"","text33":"","text34":"","text35":"","text36":"","text39":"","text4":"","text40":"","text41":"","text42":"","text43":"","text44":"","text45":"","text46":"","text47":null,"text48":"","text49":null,"text5":"","text50":"","text52":null,"text6":"","text7":"","text8":"","text9":""},{"id":1,"idejemplo":1,"t1":"","t11":"","t12":"","t13":"","t14":"","t15":"","t16":"","t17":"","t18":"","t2":"","t3":"","t4":"","t5":"","t6":"","t7":"","t8":"","text1":"<span style="color: lime;"><b>RIVAS</b></span>","text10":"","text11":"","text12":"","text13":"","text14":"","text15":"","text16":"","text17":"","text18":"","text19":"","text20":"","text21":"","text22":"","text23":"","text24":"","text25":"","text26":"","text27":"","text28":"","text29":"","text3":"","text30":"","text31":"","text32":"","text33":"","text34":"","text35":"","text36":"","text39":"","text4":"","text40":"","text41":"","text42":"","text43":"","text44":"","text45":"","text46":"","text47":"","text48":"","text49":null,"text5":"","text50":"","text52":"","text6":"","text7":"","text8":"","text9":""}]<br />
<br />
Con esto hemos finalizado este corto pero muy educativo tutorial.<br />
<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5212887449804228931.post-75920075355498190132013-02-26T09:36:00.000-04:302013-02-26T09:46:51.668-04:30Enlazando álbums en la nueva versión de picassawebDesde la migración de picassaweb a la nueva versión, desapareció la opción de Enlazar este álbum. Pues bien, si por casualidad tienes un código viejo de cuando compartiste un álbum como diapositiva, solo tienes que copiar ese código y reemplazar el id del usuario y el id del álbum que quieras compartir en la variable host del componente object.<br />
<br />
Código viejo:
<br />
<br />
<object data="http://picasaweb.google.com/s/c/bin/slideshow.swf" height="400" type="application/x-shockwave-flash" width="550"><br />
<param name="movie" value="http://picasaweb.google.com/s/c/bin/slideshow.swf" /><br />
<param name="flashvars" value="host=picasaweb.google.com&amp;hl=es&amp;feat=flashalbum&amp;RGB=0x000000&amp;feed=http%3A%2F%2Fpicasaweb.google.com%2Fdata%2Ffeed%2Fapi%2Fuser%2F<b><span style="color: yellow;">107611341400605027389</span></b>%2Falbumid%2F<span style="color: red;"><b>5567340469573655985</b></span>%3Falt%3Drss%26kind%3Dphoto%26hl%3Des" /><br />
<param name="pluginspage" value="http://www.macromedia.com/go/getflashplayer" /><br />
</object><br />
<br />
El id del usuario google esta marcado en azul y el id del álbum esta marcado en rojo.<br />
<br />
En la nueva versión web de picassa solo permite compartir el álbum como dirección url:<br />
https://plus.google.com/photos/<b><span style="color: yellow;">113536766050611718301</span></b>/albums/<span style="color: red;"><b>5627336090337889201</b></span>?authkey=CPb2iJiw5MWqbg<br />
<br />
Solo deben remplazar cada id en su respectivo lugar y listo.Unknownnoreply@blogger.com0