Mòdul 7   

Pràctica 9:Afegint funcionalitat al portal
Tornar presentació tema
    Prąctica 1 Pràctica 2 Prąctica 3 Pràctica 4 Pràctica 5 Pràctica 6 Pràctica 7 Pràctica 8 Prąctica 9 Pràctica 10
 

Fins aquesta pràctica has fet la feina més feixuga: has completat les instal·lacions i configuracions i has escrit les classes utilitàries del portal. Ara és l'hora de treure el partit d'aquesta feina, de dotar el programa de capacitats de comunicació amb l'usuari.

Repartiràs aquesta feina en dues pràctiques. En aquesta primera afegiràs les següents capacitats al portal de notícies ACME:

1) Mantenir un comptador de visites.

2) Elaborar una llista dels darrers articles publicats

3) Fer una pàgina que presenti un article

4) Votar per un article

A la darrera pràctica aprendràs a utilitzar els formularis per a enviar dades des de la pàgina web al servidor Resin.

 
Primera tasca: El comptador de visites  
 


El teu client, com pensa fer publicitat a través del portal de notícies, es preocupa molt de l'èxit de la pàgina a Internet. T'encarrega que enregistris tots els accessos que es fan al portal. De cada accés en vol saber la procedència i en quina hora s'ha produït. Això vol dir que has de mantenir un registre de milers i milers d'entrades: Ho has d'escriure necessàriament en una taula del MySQL per a què després els experts d'ACME en puguin analitzar la informació.

A més a més, vols que en el portal s'imprimeixin el número de visites totals que ha rebut la pàgina i el número de connexions en el dia actual.

Tens, doncs, les següents necessitats:

1) Has de pensar en una taula que vagi enregistrant tots els accessos.
2) Has de crear una representació Java d'aquesta taula (el POJO corresponent)
3) Has d'escriure els mètodes d'inserció i consulta de dades.

Anem fent aquestes feina:

La taula:

 
 

Obre el Query Browser i construeix una taula amb el nom visites i la següent estructura de camps:

NOM TIPUS INDEX
ID INTEGER PRIMARI
DATA TIMESTAMP SI
IP VARCHAR(15) SI
 
 


El primer camp serà el camp clau de la taula. Es diu ID, com tots els camps clau de la base de dades, i és un enter autoincremental no null. Les opcions que el Query Browser marca per defecte.

El camp DATA contindrà el dia i l'hora en què es fa la connexió. El faràs del tipus TIMESTAMP per a ferte fàcil el manteniment de la taula: els camps TIMESTAMP s'omplen per defecte amb el dia i l'hora en que es fa la inserció del registre. No cal, doncs, que l'omplis tú des del programa de Java, el MySQL ho farà sol.

El camp IP contindrà l'adreça IP del client que fa la connexió. Com les IPs no són més llargues de 15 caràcters, en fem del camp un a VARCHAR(15), camp variable de fins a 15 caràcters.

Indexa els dos camps DATA i IP per a facilitar les tasques de consulta.

 

El POJO:

Ara és l'hora de crear una classe Visita.java que representi en llenguatge Java la taula de visites. Obre el BlueJ i, en el paquet acme, escriu el següent codi:

 

 

package acme;

import java.util.Date;

/**
* @author Angel Solans
* @version 15-12-2004
* JavaBean Visita
*/
public class Visita {
    private int id; // Camp clau de la visita
    private Date data; // Data en què es produeix
    private String ip; // IP des d'on es fa la visita

    public Visita() {
    }

    public void setId(int id) {
        this.id=id;
    }
    public int getId() {
        return this.id;
    }
    public void setData(Date data) {
        this.data=data;
    }
    public Date getData() {
        return this.data;
    }
    public void setIp(String ip) {
        this.ip=ip;
    }
    public String getIp() {
        return this.ip;
    }
}

 
 


Observa com la classe té exactament la mateixa estructura de camps que la taula "Visites" del MySQL.

Les Consultes a la base de dades:

Necessitaràs fer tres accions sobre la base de dades: afegir una visita quan algú es connecti al portal; fer el recompte de visites del dia i, finalment, fer el recompte de visites totals al portal.

Has de crear, doncs, tres consultes. Obre amb el BlueJ el dipòsit de consultes (el tens a acme.util.Consultes). Afegeix les següents consultes:

 
 
A) Consulta per a afegir una visita a la taula "visites":

 

public void addVisita(Visita visita) throws SQLException {
    Connection connexio=DAOUtils.getDBConnection();
    PreparedStatement stmt = connexio.prepareStatement("INSERT INTO         VISITES (IP) VALUES (?)");
    stmt.setString(1,visita.getIp());
    stmt.execute();
    stmt.close();
    connexio.close();
}

 
 


Aquesta consulta és similiar a la que vas escriure a la pràctica anterior: obres una Connection que ens cedeix DAOUtils i quan està oberta crees un PreparedStatement amb la cadena SQL (en aquest cas una consulta d'inserció).

Observa que hi ha, però, algunes diferències remarcables:

  • No hi ha cap ResultSet. Com es tracta d'una inserció de dades lleugera, no esperes cap resposta del servidor. Executes el PreparedStatement i tanques la connexió.
  • El PreparedStatement està parametritzat: fixa't que has escrit

    "INSERT INTO VISITES (IP) VALUES (?)".

    Que es pot traduir com "Inserta a la taula de visites un registre nou. Omple tots els camp amb els valors per defecte excepte el camp IP al que li has de donar el valor del paràmetre ?". És a la següent sentència quan li dones valor al paràmetre:

    stmt.setString(1,visita.getIp());.

    que vol dir "omple el primer paràmetre que trobis a la consulta SQL amb el valor en forma de cadena de visita.getIp()". Si la consulta tingués dos paràmetres, com per exemple

    INSERT INTO VISITES (ID,IP) VALUES (?,?)

    hauries de donar valor així:

    stmt.setInt(1,un_numero_enter);
    stmt.setString(2,una_cadena);
  • El PreparedStatement s'executa amb el mètode stmt.execute(); que és un mètode void i, per tant, no retorna res.

B) Consulta per a fer el recompte de totes les visites rebudes pel portal:

 
public int getVisites() throws SQLException {
    int visites = 0;
    Connection connexio = DAOUtils.getDBConnection();
    PreparedStatement stmt = connexio.prepareStatement("SELECT         COUNT(*) AS NUMERO FROM VISITES");
    ResultSet rs = stmt.executeQuery();
    if (rs.next()) {
        visites = rs.getInt("NUMERO");
    }
    rs.close();
    stmt.close();
    connexio.close();
    return visites;
}
 
 


En aquest cas si hi ha ResultSet i has de procedir de forma similar a la consulta de la pràctica 8.

El mètode retorna un número enter que és el recompte del número de registres que hi ha a la taula "visites". En llenguatge SQL per a saber el número de registres d'una taula escrivim "SELECT COUNT(*) FROM la_taula_que_sigui". Com necessites donar-li un nom al número resultant escrius "SELECT COUNT(*) AS NUMERO FROM VISITES" i després reculls el valor d'aquest enter a la sentència visites = rs.getInt("NUMERO");

 

C) Consulta per a saber el número de visites del dia actual:

 

public int getVisitesDia() throws SQLException {
    int visites = 0;
    Connection connexio = DAOUtils.getDBConnection();
    PreparedStatement stmt = connexio.prepareStatement("SELECT         COUNT(*) AS NUMERO FROM VISITES WHERE CAST(DATA AS DATE)=         ?");
    stmt.setDate(1,new java.sql.Date(new     java.util.Date().getTime()));
    ResultSet rs = stmt.executeQuery();
    if (rs.next()) {
        visites = rs.getInt("NUMERO");
    }
    rs.close();
    stmt.close();
    connexio.close();
    return visites;
}

 
 


Aquest mètode és similar a l'anterior, has d'afegir, però, un filtre WHERE a la sentència SQL i un paràmetre per a què només compti les visites que la pàgina ha rebut en el dia actual.

Observa el tractament de les dates en Java-MySQL: per a passar un paràmetre a una consulta en forma de data:

    stmt.setDate(1,new java.sql.Date(new         java.util.Date().getTime()));

Has de construir un objecte java.sql.Date, no et serveix un java.util.Date (són objectes diferents). Pots, però, construir un objecte java.sql.Date a partir d'un java.util.Date() com ho fa el codi precedent.. En pseudocodi, la sentència anterior seria equivalent a "crea un nou objecte java.util.Date() amb la data d'avui i, a través d'aquest objecte crea un nou java.sql.Date".

A la senténcia SQL també has de fer una conversió del camp DATA: CAST(DATA AS DATE).

Com DATA és un camp TIMESTAMP, té una precisió de milisegons i no li pots passar directament el paràmetre java.sql.Date que acabes de crear. Si li passes i es compara la data '01/01/2005 12:32' del paràmetre amb la data '01/01/2005 08:45' de la taula, el servidor MySQL no les considerarà iguals perquè hi ha una variació en les hores: Has d'eliminar aquesta informació sobre l'hora.

Això és el que fa el CAST(DATA AS DATE). El tipus DATE de MySQL només conté la informació del dia. Expressada la consulta d'aquesta forma les dates '01/01/2005 12:32' i '01/01/2004 08:45' són idèntiques perquè el servidor n'extreu l'hora i les tracta com a '01/01/2005' i '01/01/2005'.

 

La pàgina web

 

Obre amb el teu editor de pàgines web la pàgina top.jsp que tens a l'arrel del projecte noticiesacme (c:/java/resin-3.0.9/webapps/noticiesacme/). Modifica-la amb el següent codi marcat en negreta:

 
<%@ page language="java" import ="java.util.GregorianCalendar,acme.util.*,acme.*"%>
<%
Consultes consultes = new Consultes();
Visita visita = new Visita();
visita.setIp(request.getRemoteAddr());
consultes.addVisita(visita);

int visitesavui = consultes.getVisitesDia();
int visitestotes = consultes.getVisites();
%>

<table width="95%" border="0" cellpadding="1">
<tr>
<td width="38%">ACME</td>
<td width="31%" valign="bottom"><%=DataUtil.getCatalanDate(new GregorianCalendar())%></td>
<td width="31%" valign="bottom"><p align="right">N&ordm; de visites: Avui <%=visitesavui%> . Total <%=visitestotes%></p></td>
</tr>
</table>


 
 


Observa que

  • Crees una instància de la classe consultes

         Consultes consultes = new Consultes();
  • Després crees un objecte de visita a la web

         Visita visita = new Visita();

    i n'omples el camp IP amb l'adreça remota del client que ha entrat al portal:

         visita.setIp(request.getRemoteAddr());
  • Amb aquesta informació, afegeixes la visita a la taula visites del MySQL.

         consultes.addVisita(visita);
  • Un cop has enregistrat la informació, fas el recompte de les visites totals i de les visites d'avui.

         int visitesavui = consultes.getVisitesAvui();
         int visitestotes = consultes.getVisites();

Verifica el funcionament del programa. Activa el Resin i accedeix al portal: http://localhost . Has d'obtenir el següent resultat:

 
 
 
 

Refresca el navegador i observa com va sumant el número de visites.

Si obres el Query Browser del MySQL i obres la taula de visites (SELECT * FROM VISITES) veuràs com s'han anat enregistrant les teves entrades al portal.

 

 
Segona tasca: Llista de darrers articles publicats i Llista d'articles més votats  
 

 

Per a llistar els darrers articles publicats necessites tres peces:

  • Una taula MySQL on enregistrar els articles. Ja la tens creada, ho vares fer a la pràctica 7.
  • Un POJO que representi els objectes "Article" i serveixi d'enllaç entre Java i la taula d'Articles.
  • Una consulta a la base de dades que retorni una matriu d'objectes "Article" amb els darrers artices publicats.

 

El POJO:

A hores d'ara, estudiant la taula que enregistra els articles a la base de dades, ja series capaç d'escriure la seva representació en Java. Per si tens dubtes, aquí tens el codi. Obre el BlueJ i escriu una nova classe que es digui Article.java amb el següent contingut:

 
package acme;

import java.util.Date;

/**
*
* @author Angel Solans
* @version 15-12-2004
*/

public class Article {
    private int id;
    private Date data;
    private String autor;
    private String titol;
    private String contingut;

    public Article() {
        id = 0;
        autor = "";
        titol = "";
        contingut = "";
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id=id;
    }
    public Date getData() {
        return data;
    }
    public void setData(Date data) {
        this.data = data;
    }
    public String getAutor() {
        return autor;
    }
    public void setAutor( String autor) {
        this.autor = autor;
    }
    public String getTitol() {
        return titol;
    }
    public void setTitol( String titol) {
        this.titol = titol;
    }
    public String getContingut() {
        return contingut;
    }
    public void setContingut( String contingut) {
        this.contingut = contingut;
    }
}

 
 

 

La consulta:

Has d'afegir un nou mètode a la classe contenidora de consultes acme.util.Consultes. Es dirà getDarrersArticles().

Actualitza, en primer lloc, les importacions que fa la la classe, afegeix a Consultes aquestes dues sentències d'importació.

import acme.Article;
import java.text.SimpleDateFormat;

Seguidament, afegeix el mètode:

 

public Article[] getDarrersArticles(int numarticles) throws   SQLException {
    Article[] articles = null;
    Article article = null;
    Vector v = new Vector();
    Connection connexio = DAOUtils.getDBConnection();
    PreparedStatement stmt = connexio.prepareStatement("SELECT * FROM         ARTICLES ORDER BY DATA DESC LIMIT ?");
    stmt.setInt(1,numarticles);
    ResultSet rs = stmt.executeQuery();
    while (rs.next()) {
        article = new Article();
        article.setId(rs.getInt("ID"));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd             hh:mm:ss");
        try {
            article.setData(sdf.parse(rs.getString("DATA")));
        }catch(Exception e) {
            article.setData(new Date());
        }
        article.setAutor(rs.getString("AUTOR"));
        article.setTitol(rs.getString("TITOL"));
        article.setContingut(rs.getString("CONTINGUT"));
        v.add(article);
    }
    rs.close();
    stmt.close();
    connexio.close();

    articles = new Article[v.size()];
    for (int n=0;n<articles.length;n++) {
        articles[n]=(Article)v.get(n);
    }

    return articles;
}

 
 


El cos del mètode et resultarà molt familiar, amb algunes novetats destacables:

  • Limites el número d'articles que retornarà la consulta: a través del paràmetre d'entrada numarticles i el paràmetre "... ORDER BY DATA DESC LIMIT ?" a la consulta SQL. Així pots decidir el número d'articles que seran retornats cada vegada que crides el mètode .
  • No pots carregar directament una data en format TIMESTAMP des del MySQL. Has de fer algun tipus o altre de traducció. En aquest cas, optem per recollir la data de la taula en format de cadena i passar aquesta cadena a una java.util.Date a través de la classe SimpleDateFormat.

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd             hh:mm:ss");
            try {
                article.setData(sdf.parse(rs.getString("DATA")));
            }catch(Exception e) {
                article.setData(new Date());
            }

Per la resta, actues com ja has fet abans: crees un vector d'articles que vas carregant tot recorrent el ResultSet sequencialment i després tradueixes el vector a una matriu d'articles que és el valor que retornes.

 

Modificacions de la pàgina index.jsp

Obre la pàgina index.jsp que és a la carpeta arrel del projecte (c:/java/resin-3.0.9/webapps/noticiesacme/). Modifica-la afegint el codi assenyalat en negreta:

 
<html>
<head>
<title>Agència de Notícies ACME</title>
</head>
<body>
<%@ include file="top.jsp"%>
<%
Article[] darrersarticles = consultes.getDarrersArticles(10);
%>

<h2>Portal de l'Agència de Notícies ACME. </h2>
<table width="100%" border="0" cellpadding="1">
<tr>
<td>&nbsp;</td>
<td><b>Darrers Articles</b><br><br>
<% if (darrersarticles!=null) for (int n=0;n<darrersarticles.length;n++) {%>
<%=darrersarticles[n].getTitol()%><br>
<% } %>

</td>
</tr>
</table>

<p>&nbsp;</p>
<%@ include file="peu.jsp"%>
</body>
</html>

 
 

La quantitat de codi que has d'afegir és minima (recorda que aquest és l'objectiu: posar el mínim de codi de programa a les pàgines web, separant la presentació de dades del seu modelat). Senzillament crees i carregues una matriu amb els darrers 10 articles:

Article[] darrersarticles = consultes.getDarrersArticles(10);

i posteriorment en fas un bucle d'impressió:

<% if (darrersarticles!=null)
     for (int n=0;n<darrersarticles.length;n++) {%>
         <%=darrersarticles[n].getTitol()%><br>
  <% } %>

Observaràs que en aquesta pàgina no instancies la classe Consultes: pensa que ja ho has fet a la pàgina top.jsp. Com aquesta darrera pàgina s'incrusta a index.jsp a l'afegir l'etiqueta < %@ include file="top.jsp"%>, tot el codi font de les dues pàgines queda compartit.

Per a veure si la consulta funciona correctement, afegeix un parell d'articles amb el Query Browser del MySQL. Pots escriure i executar dues consultes similars a aquestes:

INSERT INTO ARTICLES (AUTOR,TITOL,CONTINGUT) VALUES ('reverte','Cabo Trafalgar','Contingut de l''article')

INSERT INTO ARTICLES (AUTOR,TITOL,CONTINGUT) values ('obrian','La fragata Surprise','Contingut de l''article')

Activa el Resin si encara no ho has fet i crida el portal: http://localhost. Has d'obtenir una sortida com aquesta:

 
 
 
     
Tercera tasca: Veure un article  
     
 

Ara donaràs una mica de vida a la llista d'articles: enllaçaràs el títol de l'article a una nova pàgina dinàmica que en presentarà el contingut. Quan l'usuari faci clic sobre el títol, s'obrirà una nova finestra amb el text de l'article.

Necessitaràs:

  • Modificar la pàgina index.jsp per a crear l'enllaç del títol a la pàgina de contingut.
  • Fer una consulta a la base de dades que et retorni totes les dades d'un article.
  • Escriure una pàgina .jsp que presenti el contingut d'un article.

Modificacions a la pàgina index.jsp

Revisa la pàgina index.jsp actualitzant el cos del bucle d'impressió segons et suggerim en el fragment de codi assenyalat en negreta:

 
<html>
<head>
<title>Agència de Notícies ACME</title>
</head>
<body>
<%@ include file="top.jsp"%>
<%
    Article[] darrersarticles = consultes.getDarrersArticles(10);
%>
<h2 align="center">Portal de l'Agència de Notícies ACME. </h2>
<table width="100%" border="0" cellpadding="1">
<tr>
<td>&nbsp;</td>
<td><strong>Darrers Articles</strong><br>
<br>
<% if (darrersarticles!=null)
    for (int n=0; n<darrersarticles.length; n++) {%>
        <a href="article.jsp?id=<%=darrersarticles[n].getId()%>"           target="_blank">
            <%=darrersarticles[n].getTitol()%>
        </a>
<br>
<% } %> </td>
</tr>
</table>
<p>&nbsp;</p>
<%@ include file="peu.jsp"%>
</body>
</html>
 
 


Has d'escriure una etiqueta html d'enllaç. Aquestes etiquetes tenen aquest format:

<a href="direccio_que_s'obre_al_fer_click?parametre=valor">Text que apareix a l'enllaç</a>

Observa que podem afegir paràmetres a un enllaç. Aquests paràmetres arriven al servidor i poden ser capturats pels teus programes. Ara en veuràs un exemple. Pots passar més d'un paràmetre en un adreça web. Només et cal encadenar-los així:

http://www.domini.com?param1=valor1&param2=valor2&param3=valor3

A la pàgina index.jsp el que fas és utilitzar les etiquetes <%=%> per anar construint dinàmicament l'enllaç.

Per exemple, per a què es representi a la pàgina jsp aquest text

<a href="article.jsp?id=1"></a>

que serveix per a crear un enllaç que porta el paràmetre id amb el valor 1 ("llegeix l'article el número id del qual és 1") utilitzes

<a href="article.jsp?id=<%=darrersarticles[n].getId()%>

Fas anar les dades del programa per a parametritzar els enllaços.

Ja tens preparat l'enllaç, ara hauries de fer la consulta a la base de dades per a llegir les dades de l'article solicitat per l'usuari.

Modificacions a la classe Article.java.

Tens, però, un petit problema. Quan presentis l'article als usuaris del teu programa, segurament voldràs que aparegui el nom complet de l'autor a la pàgina web (que surti imprés "Arturo Pérez Reverte" com a nom de l'autor i no "reverte"). Aquesta informació no la tens enregistrada a la taula d'articles, on només en deses el nick. La guardes a la taula d'autors. Per tant, per a generar la informació completa sobre l'article hauràs de fer una consulta creuan les dues taules "autors" i "articles".

Com el nom complet de l'autor no forma part de l'estructura de la taula "articles", no en vas crear cap camp en el POJO corresponent.

Es que faràs, en primer lloc, és adaptar la classe article.java a aquesta nova necessitat. Crearàs un camp nou la funció del qual serà desar el nom complet de l'autor d'un article.

Obre el BlueJ i busca la classe Article.java en el paquet acme. Afegeix el camp autorComplet i publica'l amb els mètodes getter i setter:

 
private String autorComplet;

public void setAutorComplet(String autorComplet) {
this.autorComplet = autorComplet;
}
public String getAutorComplet() {
return this.autorComplet;
}
 
 


Enregistra la classe i compila.

Ara sí, ja pots continuar amb la consulta.

La Consulta

Crea un mètode getArticle() a la classe acme.util.Consultes. El mètode rebrà com a paràmetre un enter, el número id de l'article, i retornarà un objecte Article amb totes les dades de la publicació solicitada.

El contingut del mètode pot ser aquest:

 

public Article getArticle(int articleid) throws SQLException {
    Article article = new Article();
    Vector v = new Vector();
    Connection connexio = DAOUtils.getDBConnection();
    PreparedStatement stmt = connexio.prepareStatement(
       "SELECT AR.*,AU.NOM,AU.COGNOM1,AU.COGNOM2 FROM ARTICLES AR,        AUTORS AU WHERE AU.AUTOR=AR.AUTOR AND AR.ID=?");
    stmt.setInt(1,articleid);
    ResultSet rs = stmt.executeQuery();
    if (rs.next()) {
        article.setId(rs.getInt("ID"));
        SimpleDateFormat sdf =
            new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
        try {
            article.setData(sdf.parse(rs.getString("DATA")));
        }catch(Exception e) {
            article.setData(new Date());
        }
        article.setAutor(rs.getString("AUTOR"));
        article.setTitol(rs.getString("TITOL"));
        article.setContingut(rs.getString("CONTINGUT"));
        article.setAutorComplet(
            rs.getString("NOM")+" "+
            rs.getString("COGNOM1")+" "+
            rs.getString("COGNOM2") );
    }
    rs.close();
    stmt.close();
    connexio.close();
    return article;
}

 
 

 

  • El nou camp de la classe Article l'omples sumant els camps NOM, COGNOM1 I COGNOM2:

        article.setAutorComplet(
            rs.getString("NOM")+" "+
            rs.getString("COGNOM1")+" "+
            rs.getString("COGNOM2") );
       }

  • Observa com has escrit la consulta SQL tot creuant dues taules. Amb aquesta sentència:

        "SELECT AR.*,AU.NOM,AU.COGNOM1,AU.COGNOM2 FROM ARTICLES AR,            AUTORS AU WHERE AU.AUTOR=AR.AUTOR AND AR.ID=?"

Has establert una relació entre les taules "articles" i "autors": el camp autor de la taula "articles" correspon al camp autor de la taula "autors":

 
   
  i la resposta del MySQL a la nostra consulta serà aquesta taula :  
   
 

 

Ara ja només et resta escriure la pàgina web que ha d'imprimir el contingut de l'article.

La pàgina article.jsp

Escriu una nova pàgina web amb el nom article.jsp a la carpeta arrel de l'aplicació amb el següent contingut:

 

 
<%@ page language="java" import ="acme.util.*,acme.*"%>
<%
    int articleid = 0;
    try {
        articleid = Integer.parseInt(request.getParameter("id"));
    }catch(Exception e) {
    }
    Consultes consultes = new Consultes();
    Article article = consultes.getArticle(articleid);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>ACME - <%=article.getTitol()%></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<h3><%=article.getTitol()%></h3>
Per <%=article.getAutorComplet()%>
<hr>
<%=article.getContingut()%>
<hr>
<%@ include file="peu.jsp"%>
</body>
</html>

 
 

 

Procedeixes recollint el paràmetre id que has creat a la tasca anterior, protegint la seva lectura per si arriva al servidor en un format erroni (ha de ser un número enter):

   int articleid = 0;
    try {
        articleid = Integer.parseInt(request.getParameter("id"));
    }catch(Exception e) {
    }
 

Seguidament obres una instancia de la classe de consultes i en carregues les dades de l'article corresonent:

    Consultes consultes = new Consultes();
    Article article = consultes.getArticle(articleid);

 
 

 

Verifica el funcionament d'aquesta part del programa. Activa el Resin, obre el portal (http.//localhost)i pica sobre el nom d'algun article de la llista de darreres publicacions. S'ha d'obrir una nova finestra amb un contingut similar a aquest:

 
 
 
     
Quarta tasca: Votacions d'Articles  
 



Un dels avantatges del teu portal és que podrà llistar el articles que han interessat més al públic en funció de les votacions que els lectors van concedint a l'article.

Utilitzaràs una metodologia elemental: quan un lector acaba de llegir un article, si li ha interessat podrà votar per ell fent un clic sobre un enllaç. Quans més vots reculli l'article, més alt estarà a la llista de popularitat.

Això vol dir que has de posar un enllaç de votació a la pàgina article.jsp i que aquest enllaç ha de portar a una pàgina que enregistri el vot de l'usuari. Els vots es van sumant a una nova taula de votacions que també has de crear. Finalment, necessitaràs crear nous mètodes de consulta a la base de dades per a enregistrar i comptar vots.

Gràficament el control del procés que en fa l'aplicació jsp és aquest:

 
 
 
 

Al fer clic sobre l'enllaç "vota per aquest article" obriràs una pàgina jsp, vota.jsp, que només conté codi de programa. No és visible a l'usuari. Aquesta pàgina enregistrarà la votació i reenviarà la petició a la pàgina article.jsp utilitzant una etiqueta especial, l'etiqueta forward.

Posa't a la feina. En primer lloc crearàs la taula de vots.

La taula de vots

Obre el Query Browser del MySQL i crea una nova taula que es digui "votacions" i que tingui la següent estructura:

 
 
NOM TIPUS INDEX
ID INTEGER PRIMARI
ARTICLE_ID INTEGER SI
DATA TIMESTAMP SI
 
 

El camp ID és enter autoincremental i fa de clau primària. El camp ARTICLE_ID recollirà el número ID de l'article votat i, al camp DATA, enregistraràs quan es va produir la votació. Si t'interessés saber l'adreça IP del votant també la podries afegir, tot i que ara no t'ho proposem.

 

Les consultes

Necessitaràs un mètode per a enregistrar les votacions i un altre mètode per a saber quants vots ha obtingut un article.

Obre la classe acme.util.Consultes i afegeix els següents dos mètodes:

 
  El mètode per a votar  
public void vota(int articleid) throws SQLException {
    int visites = 0;
    Connection connexio = DAOUtils.getDBConnection();
    PreparedStatement stmt = connexio.prepareStatement("INSERT INTO         VOTACIONS (ARTICLE_ID) VALUES (?)");
    stmt.setInt(1,articleid);
    stmt.execute();
    stmt.close();
    connexio.close();
}

 
 

Al mètode li entra un enter (articleid) que és el número ID de l'article votat. A l'inserir el registre el MySQL anotarà automàticament la data i hora de votació.

El mètode per a saber el número de vots d'un article:

 
public int getVotacionsArticle(int articleid) throws SQLException {
    int votacions=0;
    Connection connexio = DAOUtils.getDBConnection();
    PreparedStatement stmt = connexio.prepareStatement("SELECT         COUNT(*) AS NUMERO FROM VOTACIONS WHERE ARTICLE_ID=?");
    stmt.setInt(1,articleid);
    ResultSet rs = stmt.executeQuery();
    if (rs.next()) {
        votacions = rs.getInt("NUMERO");
    }
    rs.close();
    stmt.close();
    connexio.close();
    return votacions;
}
 
 

En aquest cas, a partir del número ID de l'article, el mètode retorna un enter amb el número de votacions que ha recollit.

 

Ara has de modificar el fitxer article.jsp, situat a la carpeta arrel de l'aplicació web.

Afegeix, immediatament abans de l'etiqueta <%@ include file="peu.jsp"%> el següent codi:

 
<p><a href="vota.jsp?id=<%=article.getId()%>">
Vota per aquest article</a>. (<%=consultes.getVotacionsArticle(articleid)%>) votacions obtingudes
</p>

 
 


Aquest text

crea un enllaç cap a la pàgina que ha de gestionar el vot:

     <a href="vota.jsp?id=<%=article.getId()%>">Vota per aquest     article</a>

i imprimeix el número de votacions que té l'article:

(<%=consultes.getVotacionsArticle(articleid)%>)


Seguidament escriuràs la pàgina vota.jsp, aquella que ha de gestionar el vot i no serà visible a l'usuari:

Escriu a l'arrel de l'aplicació web una pàgina que es digui vota.jsp amb el següent contingut:

 
<%@ page language="java" import ="acme.util.*,acme.*"%>
<%
    int articleid = 0;
    try {
        articleid = Integer.parseInt(request.getParameter("id"));
    }catch(Exception e) {
    }
    Consultes consultes = new Consultes();
    consultes.vota(articleid);
%>
<jsp:forward page="/article.jsp">
<jsp:param name="id" value="<%=articleid%>" />
</jsp:forward>
 
 


En aquesta pàgina

Reculls el paràmetre id amb el número d'article a votar:

 int articleid = 0;
    try {
        articleid = Integer.parseInt(request.getParameter("id"));
    }catch(Exception e) {
    }
 

Crees una instància de la classe de consultes a la base de dades:

    Consultes consultes = new Consultes();

Fas la votació:

    consultes.vota(articleid);

I, finalment, reenvies l'usuari a la pàgina d'origen, article.jsp amb aquesta etiqueta:

<jsp:forward page="/article.jsp">
<jsp:param name="id" value="<%=articleid%>" />
</jsp:forward>

Verifica el funcionament de la tasca. Activa el Resin i crida al portal (http:/localhost) . Quan demanis un article t'apareixerà un enllaç per a votar-lo i la suma de votacions obtingudes fins ara.

Vota vàries vegades un article per a comprovar que es van afegint els vots:

 
     
 
 
     
     
 

 

Tornar al principi