Nuestro inicio es un applet que lanza una petición POST a un servlet. El servlet devuelve su habitual respuesta en modo texto al applet. Su aspecto es sencillo, arriba aparecen dos campos de edición donde el usuario puede poner el nombre y el valor del parámetro de la petición POST. El texto que genera el servlet aparecerá en el editor.
Una de los atributos de nuestro applet es un objeto de la clase Utilidades. Se puede ver en el código fuente del applet que lo usamos para varias cosas, la primera y principal es conseguir el host en el que reside el servlet:
Utilidades util = new Utilidades(); ... String pathServlet = util.getHostHTTP()+"servlet/inicialservlet";
Esto tiene una sencilla explicación, que todo aquel que haya estado en equipos de desarrollo de software puede entender. Habitualmente el desarrollo implica el uso de tres entornos: entorno de desarrollo, que tiene una versión ligera del servidor de aplicaciones, en segundo lugar un entorno de preproducción, que tiene una versión más completa del contexto real de aplicación y, por último, el entorno de producción que es en el que se despliegan estas páginas y aplicaciones. Para evitar tener que recompilar las clases cada vez que cambio de entorno, guardo en un archivo .properties la referencia al host que en cada caso estoy utilizando. Por ejemplo, en el entorno de producción la propiedad 'http.host' señala esta web que está viendo:
http.host=http://www.mi_web_final.com/
Lo que hace la clase Utilidades es cargar las propiedades de dicho archivo:
public class Utilidades {
private String archivoParametros = "parametros.properties";
private Properties prop = new Properties();
private String pathPropiedades;
public String mensajeError;
/***************************************************************************
* Carga en atributo 'prop' el archivo de propiedades
* El argumento es el path donde se encuentra el archivo de propiedades.
***************************************************************************/
public boolean cargarPropiedades( String path ) {
try {
pathPropiedades = path;
URL url = new URL( pathPropiedades + archivoParametros ); // Abro URL
prop.load( url.openStream() ); // Cargo propiedades desde InputStream de URL
return true;
}
catch (MalformedURLException e) {
mensajeError = new String( e.toString() );
return false;
}
catch (IOException e) {
mensajeError = new String( e.toString() );
return false;
}
}
....
De esta forma, cambiar de entorno supone cambiar un sencillo archivo de texto, ya que el método getHostHTTP() me devuelve siempre la URL del entorno actual:
public String getParametro(String clave, String defecto) {
String retorno = defecto;
try {
retorno = prop.getProperty(clave, defecto);
}
catch (Exception e) {
retorno = defecto;
}
finally {
return retorno;
}
}
/****************************************************************************
* Sobrecargado. Si no encuentra clave, devuelve ""
****************************************************************************/
public String getParametro(String clave) {
return getParametro(clave, "");
}
public String getHostHTTP() {
return getParametro( "http.host" );
}
Más adelante podremos ver algún otro servicio que nos da esta clase.
La conexión al servlet sigue un orden conocido:
String pathServlet = util.getHostHTTP()+"servlet/inicialservlet"; URL urlServlet = new URL( pathServlet );
URLConnection conServlet = urlServlet.openConnection(); // Abro conexión con url
Ya sabemos que en una petición GET los parámetros se mandan en la invocación al servlet y de manera explícita, inmediatamente después del nombre de éste, por ejemplo:
http://mi_host/servlet/mi_servlet?param1=valor1¶m2=valor2 ...
En una petición POST no es así, los parámetros se mandan en la petición, pero de forma "implicita".
Antes de lanzar la petición tengo que conseguir y codificar el parámetro. Para obtener su nombre y valor no hay más que dirigirse al campo de texto correspondiente, mediante getText:
String params[] = { txtParam.getText() };
String valores[] = { txtValor.getText() };
Los guardo en arrays por razones evidentes, aunque en este sencillo ejemplo sólo se manda un parámetro, el código está preparado para el uso de varios.
Debemos codificar los parámetros, puesto que el juego de caracteres que utilizan es especial. Por ejemplo, su codificación no permite espacios en blanco (que se sustituyen por el símbolo '+'). Para ello nos ayudamos de la clase Utilidades, concretamente de un método static:
//// Codifico parámetros y valores. Aunque está muy extendida, si uso codificación UTF-8 //// no pueden aparecer tildes ni eñes String paramsCodificados = Utilidades.getParamsCodificados( params, valores, "iso-8859-1");
Este método codifica uno por uno, todos los nombres y valores de los parámetros. Para ello utilizamos el método static URLEncoder.encode():
static public String getParamsCodificados( String parametros[], String valores[], String codificacion ) {
try {
StringBuffer paramsCodificados = new StringBuffer();
//// Codifica cada param y cada valor, los alamcena en StringBuffer
for ( int i = 0; i<parametros.length; i++)
paramsCodificados.append( (i==0?"":"&") + URLEncoder.encode(parametros[i], codificacion) + "=" +
URLEncoder.encode(valores[i], codificacion) );
return paramsCodificados.toString(); // Devuelve cadena con params codificados
} catch( Exception e) {
return null;
}
}
Una vez hecho esto ya estamos preparados para el envío de los parámetros, que se realiza con la llamada enviarParams( conServlet, paramsCodificados ). Este método es muy sencillo:
public void enviarParams( URLConnection con, String params ) throws IOException {
con.setDoOutput( true); // Conexión para salida
con.setUseCaches( false ); // El navegador no usa caché
PrintWriter salida = new PrintWriter( con.getOutputStream() );
salida.print( params );
salida.close();
Así de sencillo.
Es algo bastante fácil de comprender. Este servlet tiene la salida habitual, pero en vez de ser texto formateado al estilo HTML, es texto puro. Su respuesta es el conjunto de parámetros y de cabeceras de la petición:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=iso-8859-1"); // Definir tipo de salida
PrintWriter out = response.getWriter(); // Obtener flujo salida
out.println("PARAMETROS DE LA PETICION:" );
for ( Enumeration e= request.getParameterNames(); e.hasMoreElements(); ) {
String nom_par = (String) e.nextElement();
out.println(" Parámetro: " + nom_par + ". Valor: " + request.getParameter( nom_par ));
}
out.println("CABECERAS (HEADERS) DE LA PETICION:" );
for ( Enumeration e= request.getHeaderNames(); e.hasMoreElements(); ) {
String nom_h = (String) e.nextElement();
out.println(" Header: " + nom_h + ". Valor:" + request.getHeader( nom_h ));
}
}
Como todo lo anterior, de forma sencilla. El trabajo lo hace el método recibirRespuesta():
InputStreamReader streamEntrada = new InputStreamReader (con.getInputStream());
BufferedReader bfEntrada = new BufferedReader( streamEntrada );
String linea;
while ((linea = bfEntrada.readLine()) != null )
println( linea );
bfEntrada.close();