Yksinkertainen vieraskirja servlet

jel 17.04.05 00:25

Kahdella servletillä toteutettu vieraskirja tietokantaan tomcatillä.

 Tekstiversio  Arvo: 0 (4 ääntä)  Äänestä: +  -
/* 

Tämä ei ole mitenkään hienosti toteutettu, mutta toimiva vieraskirja ja varmasti saa ideoita paremman version tekoon.
DbConn.java Alustaa tietokantayhteyden.
GuestBook.java on itse vieraskirja. Linkkejä täytyy korjailla sieltä täältä jos haluaa ottaa tämän käyttöön.
Toimivana tätä voi ihmetellä http://www.digibits.net:8080/guestbook/guestbook.jsp osoitteessa. Koodattu nano/tomcat4.
Parannusehdotuksia otetaan myös vastaan. Koodia saa käyttää aivan kuten tahtoo.
Tietokanta postgresql: create database guestbook;
create TABLE guestbook (time_id timestamp, username text, www text, email text, message text);

*/


/** DbConn.java */

import java.sql.*;
import java.util.*;

public class DbConn
{
  /* You really need to fill these out. */

  private String db_hostandport = "localhost:5432";
  private String db_name = "guestbook";
  private String db_username = "YOUR_USERNAME";
  private String db_password = "YOURPASSWD";

  /* End of need to's. */

  Connection conn = null;
  public Connection  DbConn()
  {
    try
    {
      Class.forName("org.postgresql.Driver");
    }
    catch (ClassNotFoundException e)
    {
      System.out.println(e);
    }

    try
    {
      conn = DriverManager.getConnection("jdbc:postgresql://" + db_hostandport + "/" + db_name + "?user=" + db_username + "&password=" + db_password);
    }
    catch (Exception e)
    {
      System.out.println("SQLException: " + e.getMessage());
    }
    return conn;
  }
  public void destroy()
  {
    try
    {
      conn.close();
      conn = null;
    }
    catch ( Exception e )
    {
      System.out.println("DbConn Exp " + e.getMessage());
    }
  }
}

/**

GuestBook.java
Koodi on kolmessa osassa. Ennen kuin on 10 viestiä (doGet) ja jälkeen (PageChange).
AddMessage metodi lisää uudet viestit kantaan. Tässä ei kauheasti tarkistuksia ole, joka haluaa koodia
käyttää saa tehdä omansa. html koodi on tehty vain toimivaksi, sitäkin pitää jokaisen itse muutella.
css tiedoston nimi on simple.css mutta senkin saa muuttaa. Oletuksena on servletin sijainti
[domain_address:port]/guestbook/GuestBook.

*/


import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.Enumeration;
import java.sql.*;

public class GuestBook extends HttpServlet
{
  /* initiate dc connection */
  private DbConn dbconn = new DbConn();
  private Connection conn = dbconn.DbConn();
  /* address of web site. */
  private String NEW_HOST = "http://www.digibits.net:8080"; // You must change this among other changes.

  public void doGet (HttpServletRequest request, HttpServletResponse response) throws IOException
  {
     response.setContentType("text/html");
     PrintWriter out = response.getWriter();
     int count = 0;

     /* print the header information. */
     out.println("<html>");
     out.println("<head>");
     out.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />");
     out.println("<link rel=\"stylesheet\" type=\"text/css\" href=\"/guestbook/simple.css\" />");
     out.println("</head>");
     out.println("<body>");
     out.println("<div id=\"box\">");
     out.println("<div id=\"content\">");
     
     /* print 10 first topics */

     if (request.getParameter("page") != null)
     {
        try
        {
            PageChange(request, response, out, request.getParameter("page"));
        }
        catch(Exception exp) { out.println(exp); }
     }
     else
     {
       try
       {
       Statement stmt = conn.createStatement();
       ResultSet RS = stmt.executeQuery("select count(*) from guestbook");
       while(RS.next())
       { count = RS.getInt(1); } // get the count of messages
       RS.close();
       ResultSet rs = stmt.executeQuery("select to_char(time_id, 'YYYY-MM-DD HH24:MI:SS'), username, www, email, message from guestbook order by time_id desc limit 10");
       while (rs.next())
       {
         out.println("<p><table>");
         String date = rs.getString(1);
         String usrname = rs.getString(2);
         String www = rs.getString(3);
         String email = rs.getString(4);
         String message = rs.getString(5);
         out.println("<tr><td><div id=p3>" + usrname +"</div></td><td><div id=p4>" + date + "</div></td></tr>");
         out.println("<tr><td><a href=\"http://" + www + "\"><img src=\"" + NEW_HOST + "/guestbook/icon_www.gif\" alt=www border=\"0\" />
</a><br /><a href=\"mailto:"
+ email + "\"><img src=\"" + NEW_HOST + "/guestbook/icon_email.gif\" alt=email border=\"0\" /></a></td><td><div id=p5>" + message + "</div></td></tr>");
         out.println("</table>");
       }
       rs.close();
       stmt.close();
      }
      catch(Exception ex)
      {
         out.println("SQL Exception: First query - " + ex.getMessage());
      }

      /* add the links to older topics. */

      int temp = (int) count / 10;    // how many pages of topic?
      int tmp2 = count % 10;          // if there is like 12 topics
      if ( tmp2 != 0 ) { temp += 1; } // add one page more
      out.println("</p><p><br /></p><p>");
      if ( count < 11 )               // if there is isn't more than one page
      { }                             // we don't do anything
      else
      {
        int tmp_2 = 1;
        for(int i=0;i<temp;i++)
        {
           out.println("<a href=/guestbook/GuestBook?page=" + tmp_2 + "> [ " + tmp_2 + " ] </a>");
           tmp_2 += 1;
        }
      }

      /* get the new topic if it is not null. */

      try
      {
        String addmsg_name = request.getParameter("name");
        if (request.getParameter("name") != null)
        {
          String addmsg_www = request.getParameter("www");
          String addmsg_email = request.getParameter("email");
          if (request.getParameter("message") != null)
          {
            String addmsg_message = request.getParameter("message");
            if ( addmsg_message.length() < 2000 )
            {
              AddMessage(addmsg_name, addmsg_www, addmsg_email, addmsg_message);
              addmsg_name = "";
              addmsg_message = "";
            }
            String newLocation =  NEW_HOST + request.getRequestURI();
            response.setHeader("Refresh", "2; URL=" + newLocation);
          }
        }
      }
      catch(Exception exp) { out.println(exp); }

      /* add a form to get new topics */

      out.println("</p><p><form action=\"GuestBook\" method=POST>");
      out.println("<ul><li>Name or nick:");
      out.println("<li><input type=text size=15 name=name MAXLENGTH=25 /></li>");
      out.println("<li>www-address:");
      out.println("<li><input type=text size=15 name=www MAXLENGTH=30 /></li>");
      out.println("<li>email address:");
      out.println("<li><input type=text size=15 name=email MAXLENGTH=30 /></li>");
      out.println("<li>Message:");
      out.println("<li><textarea rows=4 cols=30 name=message></textarea></li>");
      out.println("<li><input type=submit value=OK></li></ul>");
      out.println("</form></p>");

      }
      out.println("</p><p><br />");
      out.println("The current (server) time is " + new java.util.Date());
      out.println("</p>");
      out.println("</div>");
      out.println("</body>");
      out.println("</html>");
  }//endofdoget

 public void doPost (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
 {
    doGet(request, response);
 }

 /* add new message to db */
 private void AddMessage (String addmsg_name, String addmsg_www, String addmsg_email, String addmsg_message)
 {
   try
   {
      Statement stmt = conn.createStatement();
      stmt.executeUpdate("insert into guestbook values ('now', '" + addmsg_name + "', '" + addmsg_www + "', '" + addmsg_email + "', '" + addmsg_message + "')");
      stmt.close();
   }
   catch(Exception e)
   { System.out.println("AddMessage error: " + e); }
 }

 private void PageChange(HttpServletRequest request, HttpServletResponse response, PrintWriter out, String page) throws IOException, ServletException
 {
   int i_page = Integer.parseInt(page);
   i_page -= 1;
   i_page = i_page * 10;
   int count = 0;

   try
   {
      Statement stmt = conn.createStatement();
      ResultSet RS = stmt.executeQuery("select count(*) from guestbook");
      while(RS.next())
      { count = RS.getInt(1); }
      RS.close();

      ResultSet rs = stmt.executeQuery("select to_char(time_id, 'YYYY-MM-DD HH24:MI:SS'), username, www, email, message from guestbook order by time_id desc limit 10 offset " + i_page + ";");
      while (rs.next())
      {
        out.println("<p><table>");
        String date = rs.getString(1);
        String usrname = rs.getString(2);
        String www = rs.getString(3);
        String email = rs.getString(4);
        String message = rs.getString(5);
        out.println("<tr><td><div id=p3>" + usrname +"</div></td><td><div id=p4>" + date + "</div></td></tr>");
        out.println("<tr><td><a href=" + www + "><img src=\"http://www.digibits.net:8080/guestbook/icon_www.gif\" alt=www border=\"0\" />
</a><br /><a href="
+ email + "><img src=\""+ NEW_HOST + "/guestbook/icon_email.gif\" alt=email border=\"0\" /></a></td><td><div id=p5>" + message + "</div></td></tr>");
        out.println("</table>");
      }
      rs.close();
      stmt.close();
    }
    catch(Exception ex)
    {
       out.println("SQL Exception" + ex.getMessage());
    }

    /* add the links to older topics. */

    int temp = (int) count / 10;    // how many pages of topic?
    int tmp2 = count % 10;          // if there is like 12 topics
    if ( tmp2 != 0 ) { temp += 1; } // add one page more
    out.println("</p><p><br /></p><p>");
    if ( count < 11 )               // if there is isn't more than one page
    { }                             // we don't do anything
    else
    {
       int tmp_2 = 1;
       for(int i=0;i<temp;i++)
       {
          out.println("<a href=/guestbook/GuestBook?page=" + tmp_2 + "> [ " + tmp_2 + " ] </a>");
          tmp_2 += 1;
        }
     }

     /* get the new topic if it is not null. */

     try
     {
        String addmsg_name = request.getParameter("name");
        if (request.getParameter("name") != null)
        {
          String addmsg_www = request.getParameter("www");
          String addmsg_email = request.getParameter("email");
          if (request.getParameter("message") != null)
          {
            String addmsg_message = request.getParameter("message");
            if ( addmsg_message.length() < 2000 )
            {
              AddMessage(addmsg_name, addmsg_www, addmsg_email, addmsg_message);
              addmsg_name = "";
              addmsg_message = "";
            }
            String newLocation = NEW_HOST + request.getRequestURI();
            response.setHeader("Refresh", "2; URL=" + newLocation); // wait 2 seconds before directing to new address
          }
        }
      }
      catch(Exception exp) { out.println(exp); }

      /* add a form to get new topics */

      out.println("</p><p><form action=\"GuestBook\" method=POST>");
      out.println("<ul><li>Name or nick:");
      out.println("<li><input type=text size=15 name=name MAXLENGTH=25 /></li>");
      out.println("<li>www-address:");
      out.println("<li><input type=text size=15 name=www MAXLENGTH=30 /></li>");
      out.println("<li>email address:");
      out.println("<li><input type=text size=15 name=email MAXLENGTH=30 /></li>");
      out.println("<li>Message:");
      out.println("<li><textarea rows=4 cols=30 name=message></textarea></li>");
      out.println("<li><input type=submit value=OK></li></ul>");
      out.println("</form></p>");
   }
}//endofclass
 

jme 09:25 17.4.05 
Muutama ehdotus: :)

Voisit pistää DbConn luokan konstruktoriin parametreiksi käyttäjätunnuksen, salasanan, tietokannan osoitteen ja portin. Jos myöhemmin käytät samaa luokkaa, niin sinun ei tarvitse muuttaa koodia.
Sinuna siirtäisin servleteistä kaiken sql-pohjaiset toiminnot erilliseen luokkaan.
Lisäharjoituksena voisit myös siirtää kaiken html-koodin jsp-tiedostoihin ja sitten toteutat vieraskirjan sisällön näyttämisen niissä joko suoraan sisälletyn Java-koodin/custom tagien ja JavaBean:ien kanssa.

Ajattele, jos joskus haluat muuttaa vieraskirjan ulkonäköä. Nyt sinun pitää koodata se uudelleen. Jsp-tiedoston muokkaaminen onkin sitten paljon helpompaa.

editoitu: 12:47 19.4.05
harja 15:26 18.4.05 
Tuossa edellisessä kommentissa olikin jo puututtu suurimpaan osaan virheistä.
Nyrkkisääntönä voidaan pitää, että metodien pituus tulisi olla noin yhden ruudullisen verran. Tässä kaksi metodia ja satoja rivejä koodia. Ei hyvä.
Yritä löytää tuosta vieraskirjastasi yleiset "luokat", joita pystyisit hyödyntämään paremmin. Selkeästi voidaan tehdä luokka, jota tämä Servlet vain nimellisesti kutsuu toiminnallisuuden saamiseksi.

Harjoitusta vain, sillä sitä oppii. Tästä ei kyllä kenenkään kannata ottaa mallia.
editoitu: 18:17 18.4.05
jel 18:17 18.4.05 
Juu, ihan hyviä ehdotuksia. Yritän muuttaa tuota useampiin luokkiin ja siirtää html:ää jsp sivulle kun vain ehdin.
JavaBeaneista ei kokemusta ole, mutta kiinnostusta olisi kyllä tuo niilläkin toteuttaa. Mutta ehkä sitten seuraavassa
projektissa ...
jme 12:08 19.4.05 
mikefast:

"Onpas kerrassaan huonosti toteutettu. " Ton osan olisit ehkä voinut jättää kirjoittamatta tai muotoilla uudestaan. :)
Minusta tuollaiset kommentit eivät ylläpidä palstan mukavuutta. Muuten kommenttisi oli asiallinen meilestäni.

Jos minä julkaisisin palan koodia niin en mielelläni halua kuulla siitä herjaa vaan asiallista (vaikkakin kritiikkiä) palautetta.

On tarpeellisempaa kuulla, miksi kyseinen tapa on huono kuin, että se on huono.

editoitu: 12:50 19.4.05
harja 12:47 19.4.05 
jme, oikeassa olet. Otin rujuon alun pois. Pahoittelen.

Silti on aihetta mietittiä, miksi koodikirjasto on tehty. Onko kyseessä paikka, johon laitetaan koodia, "koska nyt satuin tekemään tällaisen" vai siksi, että siitä olisi ehkä teknisesti/ideallisesti jotain hyötyä muille palstan käyttäjille. Tietysti palautteen tulisi olla asiallista ja siksi myös itse perustelin vastauksessani, mihin ohjelmointiteknisiin asioihin tulisi kiinnittää huomiota. Itse koodin pisteytykseen en yleensä jaksa puuttua, ellei kyseessä ole jotain täysin käsittämätöntä tai yksinkertaisen loistavaa.

:)Mikko
editoitu: 14:20 19.4.05
jme 14:20 19.4.05 
Mutta kuka päättää mikä on hyvin tai huonosti tehty? :)

Jos tänne halutaan ainoastaan "hyviä" esimerkkejä, tulisi jokaisen julkaisun käsitellä siihen valtuutettu "guru" joka teke tämän päätöksen. Jos julkaisu
läpäisee seulan, pääsee se tälle palstalle, muuten banaanilaatikossa takaisin tekijälle (mielellään selityksen kera).

Vaikea sanoa se oikea tapa. Yksi tapa on kait ystävällisesti mutta painottaen kehottaa tekijöitä miettimään vähän tarkemmin omaa koodiansa, ennenkuin sen tänne lykkää.

Edit: typoja
The mezum 10:51 25.1.08 
saako tuosta ottaa mallia? tai vaika koko koodiN?