niedziela, 23 maja 2010

Integracja JSF i Spring

Przygotowanie środowiska
Tradycyjną drogą integracji JSF i Springa było odwoływanie się z managed beans do spring beans z użyciem tradycyjnych metod wstrzykiwania kontekstu aplikacji. W poniższym artykule pokażę jak można zastąpić managed beans których używamy w technologi JSF, spring beanami które tworzy i udostępnia Spring.
Zacznijmy więc od ściągnięcia odpowiednich bibliotek do Springa które możemy umieścić w katalogu WebContent/WEB-INF/lib naszej aplikacji (zakładam że dysponujesz już jakąś aplikacją z wykorzystaniem JSF, jeśli nie to polecam zajrzeć najpierw do artykułu JSF + Tomcat 6 + Eclipse - Hello World). Linki do potrzebnych bibliotek zamieszam poniżej:

Spring - stworzenie beana
Zacznijmy od stworzenia prostego beana springowego. Do tego celu potrzebować będziemy prostej klasy javowej z jedną metodą (getHello()) która wypisz na ekran napisz powitalny (pamiętajmy o tym że bean ten będzie wykorzystany w JSF dlatego metody wypisujące napis na ekran mają prefiks get).
package com.blogspot.mkorwel.spring;

import org.springframework.stereotype.Component;

/**
 * 
 * @author Mateusz Korwel
 *
 */
@Component
public class HelloBean {

 public String getHello() {
  return "Hello Spring";
 }

}

Klasa HelloBean jest opatrzona adnotacją @Component co sugeruje że będzie to bean springowy. Następnym krokiem konfiguracji springa będzie stworzenie pliku konfiguracyjnego. W moim przykładzie plik ten znajduję się w katalogu WebContent/WEB-INF i nazywa się applicationContext.xml.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 <context:component-scan base-package="com.blogspot.mkorwel.spring" />

</beans>

Jest to tradycyjny plik konfiguracyjne do springa, z wpisem który wskazuje springowi w jakich pakietach znajdują się spring beany (czyli wszystkie klasy które opatrzone są adnotacją @Component o której już wspomniałem).

Integracja
Do integracji Springa i JSF będziemy musieli zmodyfikować plik WebContent/WEB-INF/web.xml i WebContent/WEB-INF/faces-config.xml. Do pliku web.xml dodajemy informacje o springowym kontekście aplikacji:
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <listener>
  <listener-class>
   org.springframework.web.context.request.RequestContextListener</listener-class>
 </listener>

 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/applicationContext.xml</param-value>
 </context-param>
a do pliku faces-config.xml informację o wykorzystanie spring beanów jako managed beanów
<application>
  <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
 </application>

Użycie nowej funkcjonalności
Kiedy wszystko jest już skonfigurowane możemy wykorzystywać nasze spring beany jako managed beany, do tego celu stworzyłem prostą stronkę hello.jsp (w katalogu WebContent):
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="f"  uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h"  uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>JSF Spring</title>
</head>
<body>
<f:view>
<h:outputText value="#{helloBean.hello}"></h:outputText>
</f:view>
</body>
</html>

Po umieszczeniu naszej aplikacji (nazwa mojej aplikacji to JSFSpring) na serwerze i uruchomieniu (http://localhost:8080/JSFSpring/hello.jsf) na stronie powinien pojawić się napisz Hello Spring.

środa, 19 maja 2010

Adnotacje

Adnotacje (ang. annotations) są dostępne w javie od wersji 1.5 i służą do opisywania klas. W poniższym artykule opowiem jak szybko stworzyć i wykorzystać własne adnotacje.

Tworzenie adnotacji
Definicja pustej adnotacji nie różni się specjalnie od definicji pustego interfejsu. Pomijając znaczek @ w słówku @interface w zasadzie nie ma żadnej różnicy.
package com.blogspot.mkorwel.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotationMethod {

}
Stworzenie adnotacji wymaga jeszcze użycia metaadnotacji. Poniżej umieszczam krótki opis:
  • @Target określa miejsce stosowania adnotacji
  • @Retention określa trwałość adnotacji
  • @Documented ujęcie danej adnotacji w dokumencie Javadoc
  • @Inherited zezwolenie na dziedziczenie adnotacji w podklasach

Możliwe argumenty dla metaadnotacji @Target to:
  • ElementType.TYPE - w deklaracji klasy, interfejsu, adnotacji, enum
  • ElementType.CONSTRUCTOR - w deklaracji konstruktora
  • ElementType.FIELD - w deklaracji pola
  • ElementType.LOCAL_VARIABLE - w deklaracji zmiennej lokalnej
  • ElementType.METHOD - w deklaracji metody
  • ElementType.PACKAGE - w deklaracji pakietu
  • ElementType.PARAMETER - w deklaracji parametru

Możliwe argumenty dla metaadnotacji @Retention to:
  • RetentionPolicy.SOURCE - adnotacje unieważnione przez kompilator
  • RetentionPolicy.CLASS - adnotacje widoczne w plikach klas, unieważnione przez maszynę wirtualną
  • RetentionPolicy.RUNTIME - adnotacje podtrzymywane w maszynie wirtualnej w czasie wykonania, a więc nadające się do odczytu za pośrednictwem refleksji

Poniżej stworzymy jeszcze jedną adnotację która będzie używana przy deklaracji klas (@Target(ElementType.TYPE)). Adnotacja będzie zawierała dwa elementy. Poniżej kod:
package com.blogspot.mkorwel.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotationClass {

 public int id() default -1;
 
 public String name();
 
}
Elementy w adnotacjach deklarujemy podobnie do metod w intefejsie. Każdy element może mieć wartość domyślną, aby ustalić taką wartość używamy słówka default.

Wykorzystanie adnotacji
Po stworzeniu dwóch naszych adnotacji, możemy użyć ich w naszej klasie. Kod klasy nie jest zbyt skomplikowany, więc nie będę go opisywał.
package com.blogspot.mkorwel;

import com.blogspot.mkorwel.annotation.MyAnnotationClass;
import com.blogspot.mkorwel.annotation.MyAnnotationMethod;

@MyAnnotationClass(id = 1, name = "Mateusz")
public class MyClass {
 
 @MyAnnotationMethod
 public void test(){
  
 }

}

Kiedy mamy już adnotacje i klasę która jest nimi opisana, możemy stworzyć klasę która wykorzysta nasze adnotacje i wypisze komunikat na ekranie. Kod klasy która to robi znajduje się poniżej:
package com.blogspot.mkorwel;

import com.blogspot.mkorwel.annotation.MyAnnotationClass;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
public class Test {

 public static void main(String[] args) {

  // tworzenie klasy
  MyClass myClass = new MyClass();
  Class clazz = myClass.getClass();

  // pobranie adnotacji w klasie
  for (int i = 0; i < clazz.getAnnotations().length; i++) {
   // wypisanie adnotacji
   System.out.println("Nazwa adnotacji: " + clazz.getAnnotations()[i]);
   System.out.println("Wartość atrybutu id: "
     + ((MyAnnotationClass) clazz.getAnnotations()[i]).id());
   System.out.println("Wartość atrybutu name: "
     + ((MyAnnotationClass) clazz.getAnnotations()[i]).name());
  }

  // pobranie wszystkich publicznych/pakietowych metod z klasy MyClass
  for (int i = 0; i < clazz.getMethods().length; i++) {
   // pobranie wszystkich adnotacji przypisanych do metody
   for (int j = 0; j < clazz.getMethods()[i].getAnnotations().length; j++) {
    // nazwa metody z adnotacją
    System.out.println("\nNazwa metody z adnotacją: "
      + clazz.getMethods()[i].getName());
    // wypisanie adnotacji
    System.out.println("Nazwa adnotacji: "
      + clazz.getMethods()[i].getAnnotations()[j]);
   }
  }
 }
}
Krótko opiszę co powyższa klasa robi. W pierwszej pętli for pobieramy wszystkie adnotacje które są przypisane do klasy. W naszym przypadku jest to tylko jedna adnotacja @MyAnnotationClass z dwoma elementami które zostaną również wypisane. Druga pętla for pobiera metody jakie znajdują się w klasie, a następnie pobiera adnotacje przypisane do kolejnych metod. W naszym przypadku będzie wypisana jedna metoda test() z jedną adnotacją @MyAnnotationMethod.

niedziela, 9 maja 2010

EJB + Servlet: Prosta aplikacja enterprise

Przygotowanie środowiska pracy.
Do stworzenia aplikacji użyłem:
- Eclipse jako IDE
- JBoss jako serwer aplikacji na którym będzie uruchamiana cała aplikacji

Projekt EAR
Zaczniemy od stworzenia Enterprise Application Project (EAR). Aplikacja będzie zawierała dwa moduły:
  • EJB - projekt zawierajacy ziarna EJB
  • WAR - projekt zaweirający cały widok aplikacji
To właśnie tą aplikację będziemy deployować na serwerze JBoss.

W Eclipse Enterprise Application Project tworzymy w następujący sposób. Klikamy w File -> New -> Other ... i wybieramy Enterprise Application Project.

Następnie wybieramy Target runtime, wpisujemy nazwę aplikacji i klikamy Finish.

Projekt jest na razie pusty i zostanie uzupełniony w dalszej części artykułu.

Projekt EJB
EJB czyli Enterprise JavaBeans, aby móc korzystać z tej technologi musimy stworzyć projekt EJB. W Eclipse tworzymy go w następujący sposób: Klikamy w File -> New -> Other ... i wybieramy EJB Project.

Następnie wpisujemy nazwę projektu, wybieramy wersję EJB (my będziemy korzystać z wersji 3.0) oraz zaznaczamy że nasz projekt będzie częścią dużej aplikacji enterprise.

Po kliknięciu Next > odznaczamy chęć stworzenia EJB Client JAR.

W momencie gdy mamy już przygotowany projekt możemy utworzyć pierwsze ziarno EJB. Tak więc tworzymy zwykły interfejs w dowolnym pakiecie. U mnie wygląda to tak:
package com.blogspot.mkorwel.ejb;

import javax.ejb.Local;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
@Local
public interface HelloLocal {

 public String getHelloWorld();
}

Interfejs kończy się sufiksem Local, co sugeruje że interfejs jest lokalny(w EJB występuje również interfejs Zdalny (Remote)). Rodzaj interfejsu deklarujemy używając adnotacji @Local lub @Remote.

Teraz tworzymy klasę która będzie implementację interfejsu HelloLocal.
package com.blogspot.mkorwel.ejb;

import javax.ejb.Stateless;

@Stateless
public class HelloBean implements HelloLocal {

 @Override
 public String getHelloWorld() {

  return "Hello World";
 }

}

Aby klasa stała się ziarnem EJB wystarczy użyć adnotacji @Stateless lub @Stateful. Adnotację określają czy ziarno EJB jest bezstanowe (Stateless) czy stanowe (Stateful). My tworzymy komponent bezstanowy dlatego użyliśmy adnotacji @Stateless. Nasza metoda getHelloWorld() zwraca prosty napis Hello World który wypiszemy w serwlecie.

Projekt WAR
Następnym krokiem do stworzenia naszej przykładowej aplikacji jest utworzenie projektu dla warstwy widoku, czyli zwykłego projektu WEB'owego w którym będą znajdowały się strony HTML, JSP, Servlety itd. W Eclipse klikamy w File -> New -> Other ... i wybieramy Dynamic Web Project.

Wpisujemy nazwę i nie zapominamy o dodaniu projektu do naszej aplikacji enterprise.

Następnie klikamy Finish. Teraz musimy jeszcze ustawić zależność w projekcie, tak aby mieć dostęp do klas z projektu EJB. Robimy to poprzez kliknięcie lewym przyciskiem myszy na projekcie helloWAR, wybranie Java Build Path a następnie Projects.

Klikamy w Add aby dodać zależność do projektu. Wybieramy nasz project EJB czyli helloEJB. Klikamy OK.


Teraz tworzymy zwykły servlet (w mnie nazywa się Hello), który wypisze prosty napis Hello World który zdefiniowaliśmy w projekcie EJB. Kod servletu wygląda następująco.
package com.blogspot.mkorwel.ejb;

import java.io.IOException;
import java.io.PrintWriter;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
public class Hello extends HttpServlet {
 private static final long serialVersionUID = 1L;

 @EJB
 private HelloLocal hello;

 public Hello() {
  super();
 }

 protected void doGet(HttpServletRequest request,
   HttpServletResponse response) throws ServletException, IOException {
  PrintWriter out = response.getWriter();

  out.println(hello.getHelloWorld());
 }

}

Jak widzimy jest to zwykły servlet który wywoła nam metodę getHelloWorld() z interfejsu HelloLocal. Za pomocą adnotacji @EJB wstrzykniemy implementację naszego interfejsu (klasę HelloBean.java która znajduje się w projekcie helloEJB).

Tak przygotowaną aplikację może zdeployować na serwerze JBoss. Aplikacja będzie znajduje się po linkiem 127.0.0.1:8080/helloWAR/Hello. Zauważmy że deployujemy aplikację EAR, a w przeglądarce odwołujemy się projektu WAR. Dzieje się tak dlatego że projekt helloWAR jest modułem aplikacji helloEAR.

sobota, 1 maja 2010

JavaMail: Wysłanie emaila

W poniższym artykule zademonstruje jak łatwo można napisać kod, który wysyła wiadomości email. Wysyłanie wiadomości odbędzie się przy pomocy naszego konta na gmail'u, więc nie będzie potrzebne instalowanie serwerów smtp, itd.

Przygotowanie projektu
Pierwszym krokiem jakim musisz wykonać jest założenie sobie konta na googlach. Następnie potrzebujemy jeszcze biblioteki Java Mail dzięki której będziemy mogli wysyłać maile. Plik jar możemy ściągnąć z oficjalnej strony Java Mail Api. Po ściągnięciu i rozpakowaniu, plik mail.jar przenosimy do katalogu bibliotek w naszym projekcie.

Proste wysłanie maila
Oto prosty kod dzięki któremu wyślemy bardzo prostą wiadomość:
package com.blogspot.mkorwel.mail;

import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
public class SendMail {

 private static final String HOST = "smtp.gmail.com";
 private static final int PORT = 465;
 // Adres email osby która wysyła maila
 private static final String FROM = "mateusz.korwel@gmail.com";
 // Hasło do konta osoby która wysyła maila
 private static final String PASSWORD = "xxx";
 // Adres email osoby do której wysyłany jest mail
 private static final String TO = "mateusz.korwel@gmail.com";
 // Temat wiadomości
 private static final String SUBJECT = "Hello World";
 // Treść wiadomości
 private static final String CONTENT = "To mój pierwszy mail wysłany za pomocą JavaMailAPI.";

 public static void main(String[] args) {
  try {
   new SendMail().send();
  } catch (MessagingException e) {
   e.printStackTrace();
  }
 }

 public void send() throws MessagingException {

  Properties props = new Properties();
  props.put("mail.transport.protocol", "smtps");
  props.put("mail.smtps.auth", "true");

  // Inicjalizacja sesji
  Session mailSession = Session.getDefaultInstance(props);

  // ustawienie debagowania, jeśli nie chcesz oglądać logów to usuń
  // linijkę poniżej lub zmień wartość na false
  mailSession.setDebug(true);

  // Tworzenie wiadomości email
  MimeMessage message = new MimeMessage(mailSession);
  message.setSubject(SUBJECT);
  message.setContent(CONTENT, "text/plain; charset=ISO-8859-2");
  message.addRecipient(Message.RecipientType.TO, new InternetAddress(TO));

  Transport transport = mailSession.getTransport();
  transport.connect(HOST, PORT, FROM, PASSWORD);

  // wysłanie wiadomości
  transport.sendMessage(message, message
    .getRecipients(Message.RecipientType.TO));
  transport.close();
 }
}

Powyższy kod wysyła bardzo prostą wiadomość email. A co jeśli chcieli byśmy sformatować naszą wiadomość przy pomocy znaczków html? Powyższy kod wysłał by całą zawartość maila bez żadnej transformacji, ale wystarczy że zmienimy typ mime naszej wiadomości i treść zostanie sformatowana. Obecnie mamy text/plain a potrzebujemy text/html. Po takiej zmianie możemy wysyłać maila z kodem html.

Wysłanie maila z załącznikiem
Oto prosty kod dzięki któremu wyślemy wiadomość z załącznikiem:
package com.blogspot.mkorwel.mail;

import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.FileDataSource;
import javax.activation.DataHandler;

import java.util.Properties;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
class SendMailAttachment {

 private static final String HOST = "smtp.gmail.com";
 private static final int PORT = 465;
 // Adres email osby która wysyła maila
 private static final String FROM = "mateusz.korwel@gmail.com";
 // Hasło do konta osoby która wysyła maila
 private static final String PASSWORD = "xxx";
 // Adres email osoby do której wysyłany jest mail
 private static final String TO = "mateusz.korwel@gmail.com";
 // Temat wiadomości
 private static final String SUBJECT = "Hello World";
 // Treść wiadomości
 private static final String CONTENT = "To mój pierwszy mail z załącznikami wysłaby za pomocą JavaMailAPI.";
 // Ścieżka do pliku
 private static final String PATH_FILE = "zalacznik.txt";

 public static void main(String[] args) {
  try {
   new SendMailAttachment().send();
   System.out.println("Wiadomość wysłana");
  } catch (MessagingException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

 void send() throws MessagingException {

  Properties props = new Properties();
  props.put("mail.transport.protocol", "smtps");
  props.put("mail.smtps.auth", "true");

  // Pobranie sesji
  Session mailSession = Session.getDefaultInstance(props, null);

  // Tworzenie wiadomości
  MimeMessage message = new MimeMessage(mailSession);
  message.setSubject(SUBJECT);

  // Stworzenie części wiadomosci z treścią
  MimeBodyPart textPart = new MimeBodyPart();
  textPart.setContent(CONTENT, "text/html; charset=ISO-8859-2");

  // Stworzenie części z załacznikami
  MimeBodyPart attachFilePart = new MimeBodyPart();
  FileDataSource fds = new FileDataSource(PATH_FILE);
  attachFilePart.setDataHandler(new DataHandler(fds));
  attachFilePart.setFileName(fds.getName());

  // Zestawienie obydwu części maila w jedną wieloczęściową
  Multipart mp = new MimeMultipart();
  mp.addBodyPart(textPart);
  mp.addBodyPart(attachFilePart);

  // Dodanie treści maila
  message.setContent(mp);
  message.addRecipient(Message.RecipientType.TO, new InternetAddress(TO));

  Transport transport = mailSession.getTransport();
  transport.connect(HOST, PORT, FROM, PASSWORD);

  // Wysąłnei maila
  transport.sendMessage(message, message
    .getRecipients(Message.RecipientType.TO));
  transport.close();
 }
}

Powyższego kodu chyba nie trzeba komentować. Jedną różnicą maila z załącznikami od maila bez załączników jest to, że wiadomość składa się z kilku części.

wtorek, 27 kwietnia 2010

Wysłanie SMS w Javie

Zaczniemy od ściągnięcia dwóch niezbędnych bibliotek:
Po ściągnięciu i rozpakowaniu pliki .jar kopiujemy do projektu i ustawiamy zależności.

Założenie bezpłatnego konta na ipipi.com
Do wysyłania sms będziemy potrzebowali serwera smtp. Do tego celu możemy założyć konta na ipipi.com. Założenie konta jest darmowe. Do konta dostaniemy możliwość wysłania 3 testowych wiadomości, za kolejne trzeba już niestety zapłacić (kupno pakietu).
Wchodzimy na stronę rejestracji i wypełniamy wszystkie potrzebne pola (login, hasło, email, telefon, imię, nazwisko i kraj). Na podany numer telefony zostanie nam wysłana wiadomość z kodem dostępu który będziemy musieli podać w następnym etapie rejestracji.
Strona rejestracji

Kod klasy
Po założeniu konta możemy napisać naszą pierwsza klasę do wysyłania sms'ów za pośrednictwem ipipi.com.

package com.blogspot.mkorwel.sms;

import java.util.Properties;
import java.util.Date;
import javax.mail.*;
import javax.mail.internet.*;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
public class SMSSend {

 // login z portlau ipipi.com
 private static String USERNAME = "xxx";
 // hasło z portalu ipipi.com
 private static String PASSWORD = "xxxyyyzzz123";
 private static String SMTP_HOST = "ipipi.com";
 // podajemy nazwe swojego konta w serwicie ipipi.com
 private static String FROM = "xxx@ipipi.com";
 // podajemy numer na który wysyłamy sms'a
 private static String TO = "+48123456789@sms.ipipi.com";
 // Wpisujemy temat naszej wiadomości
 private static String SUBJECT = "Moja pierwsza wiadomość";
 // Wpisujemy temat naszej wiadomości
 private static String BODY = "Hello World!!!";

 public static void main(String[] args) {

  SMSSend smsSend = new SMSSend();
  smsSend.sendSMS();
  System.out.println("WIADOMOSZ WYSLANA");

 }

 public void sendSMS() {

  Transport tr = null;

  try {
   // ustawiamy parametry
   Properties props = System.getProperties();
   props.put("mail.smtp.auth", "true");

   // pobieramy sesję obiektu
   Session mailSession = Session.getDefaultInstance(props, null);

   // Tworzymy wiadomość
   Message msg = new MimeMessage(mailSession);
   msg.setFrom(new InternetAddress(FROM));
   msg.setSubject(SUBJECT);
   msg.setText(BODY);
   msg.setSentDate(new Date());

   // ustawiamy odbiorcę wiadomości
   InternetAddress[] address = { new InternetAddress(TO) };
   msg.setRecipients(Message.RecipientType.TO, address);

   tr = mailSession.getTransport("smtp");
   tr.connect(SMTP_HOST, USERNAME, PASSWORD);
   msg.saveChanges();

   // wysyłamy sms'a
   tr.sendMessage(msg, msg.getAllRecipients());
   tr.close();
  } catch (Exception e) {
   System.out.println("Error");
   e.printStackTrace();
  }
 }
}

Jeśli wszystko poszło dobrze możemy cieszyć się wysyłaniem sms'ów.

czwartek, 15 kwietnia 2010

Spring Hello World

W poniższym artykule pokaże jak w bardzo prosty sposób użyć Springa. Do tworzenia kodu użyłem edytora Eclipse z zainstalowaną wtyczką SpringIDE (podaję linka za pomocą którego możemy zainstalować plugin w eclipse http://dist.springframework.org/release/IDE).


Przygotowanie środowiska
Na początek musimy ściągnąć z internetu następujące jary:


Całą paczkę jarów ze springiem można sciągnąć z oficjalnej strony springa.
Kiedy już będziemy mieli je na dysku, proponuję stworzyć w projekcie oddzielny katalog na biblioteki np. lib i umieścić tam ściągnięte jary. Następnie dodajemy biblioteki do projektu.

Tworzenie beana
Zaczniemy od stworzenia prostej klasy która będzie springowym beanem. Tak więc tworzymy pakiet com.blogspot.mkorwel a w nim klase Osoba.java. W klasie Osoba tworzymy pole imie typu String wraz z metodami get i set. Całość powinna wyglądać tak:

package com.blogspot.mkorwel;

/**
 * 
 * @author Mateusz Korwel
 *
 */
public class Osoba {

 private String imie;

 public void setImie(String imie) {
  this.imie = imie;
 }

 public String getImie() {
  return imie;
 }

}

Prosta klasa jest gotowa, aby stała się springowym beanem musimy umieścić odpowiedni wpis w odpowiednim pliku konfiguracyjnym. Tak wiec za pomocą wtyczki SpringIDE tworzymy Spring Bean Configuration File. Klikamy na projekcie prawym przyciskiem, wybieramy New -> Other... -> Spring -> Spring Bean Configuration File




klikamy Next > 




po wpisaniu nazwy (u mnie beans.xml) i kliknięciu Next >




musimy jeszcze wybrać schemę, beans -> spring-beans-3.0.xsd. Po tym wszystkim powinien stworzyć się prosty plik xml w którym będziemy umieszczać wszystkie beany. Cały plik po dodaniu wpisu z naszą klasą Osoba powinien wyglądać tak:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 <bean id="osoba" class="com.blogspot.mkorwel.Osoba">
  <property name="imie" value="Mateusz"></property>
 </bean>

</beans>

W elemencie bean tworzymy instancje danej klasy według wzorca Singleton (czyli obiekt jednej instancji wykorzystywany w całej aplikacji). W atrybucie id deklarujemy identyfikator beana, a w class podajemy ścieżkę do pliku. Po takiej deklaracji mamy już zainicjalizowaną naszą klasę i możemy jej używać wszędzie w aplikacji. Element property jest opcjonalny i mówi o wartościach z jakimi tworzony jest bean (wywołanie metody setImie (atrybut name) z wartością Mateusz (atrybut value)).

Stworzenie prostego JUnite
Aby przetestować czy bean tworzy się poprawnie, tworzymy prosty JUnite test w którym będziemy wstrzykiwać naszą instancję klasy i sprawdzać czy wartość w polu imię jest Mateusz.
Cały kod testu ma wygląda tak:

package com.blogspot.mkorwel;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:beans.xml" })
public class OsobaTest {

 @Autowired
 @Qualifier("osoba")
 private Osoba osoba;

 @Test
 public void testImie() {

  Assert.assertEquals("Mateusz", osoba.getImie());

 }

}


Jak widzimy jest to zwykły test JUnit z kilkoma springowymi adnotacjami. Najważniejsza adnotacja to oczywiście @ContextConfiguration która wstrzykuje nam kontekst naszej aplikacji. Możemy sami podać miejsce gdzie jest zlokalizowany nasz plik konfoguracyjny beans.xml poprzez ustawienie pola locations, jesli tego nie zrobimy to aplikacja odwoła się do pliku który znajduje się w tym samym pakiecie co klasa o nazwie naszej klasy z końcówką -context.xml (w naszym wypadku był by to plik com/blogspot/mkorwel/OsobaTest-context.xml). Kolejne dwie ważne adnotacje to @Autowired@Qualifier. Adnotacja @Autowired wstrzykuje nam instancję klasy Osoba do pola osoba, a @Qualifier wskazuje na konkretne id instancji (w wypadku gdy plik beans.xml zawierał by kilka instancji klasy Osoba) która ma zostać wstrzyknięta. Adnotacja @RunWith wskazuje nam klasę z jaką ma się uruchomić test.

poniedziałek, 12 kwietnia 2010

Proste parsowanie XML w Javie

Co to jest XML?
XML (Extensible Markup Language) czyli niezależny od platformy sposób przechowywania, przekazywania pewnej porcji informacji.
Poniżej bardzo prosty przykład pliku XML zawierającego informacje o osobach (imię, nazwisko, płeć):
<?xml version="1.0"?>
<osoby>
  <osoba plec="mężczyzna">
   <imie>Jan</imie>
   <nazwisko>Kowalski</nazwisko>
  </osoba>
  <osoba plec="kobieta">
   <imie>Anna</imie>
   <nazwisko>Nowak</nazwisko>
  </osoba>
</osoby>


Jak skutecznie przetworzyć XML wykorzystując język Java?
Jest wiele API których można użyć do parsowania XML'i, ja pokaże dwa z nich:


  • DOM
  • SAX
DOM
Pierwszy sposób przetwarzania plików XML to Document Object Model, w skrócie DOM. Prosty API dzięki któremu możemy w łatwy sposób przeszukać plik XML i wyciągnąć z niego interesujące nas informacje. Plik XML jest wczytywane w całości do pamięci i odpowiednimi metodami możemy wyciągać z niego informacje nas interesujące. Metoda ta jest oczywiście niezalecana w przypadku dużych plików XML. Zaletą tego rozwiązania jest to, że w każdej chwili mamy dostęp do całego drzewa dokumentu, czyli do wszystkich elementów, atrybutów, wartości, itd.
Poniżej prosty kawałek kodu który czyta plik XML podany we wstępie artykułu.
package com.blogspot.xml.dom;

import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 
 * @author Mateusz Korwel
 *
 */
public class SampleDOM {

  public static void main(String argv[]) {

   try {
   File file = new File("myFile.xml");
   DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
   DocumentBuilder db = dbf.newDocumentBuilder();
   Document doc = db.parse(file);
   doc.getDocumentElement().normalize();

    System.out.println("Element główny: "
     + doc.getDocumentElement().getNodeName());
   
   NodeList nodeLst = doc.getElementsByTagName("osoba");

    for (int s = 0; s < nodeLst.getLength(); s++) {

     Node fstNode = nodeLst.item(s);

     if (fstNode.getNodeType() == Node.ELEMENT_NODE) {

      Element fstElmnt = (Element) fstNode;

      NodeList fstNmElmntLst = fstElmnt
       .getElementsByTagName("imie");
     Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
     NodeList fstNm = fstNmElmnt.getChildNodes();

      NodeList lstNmElmntLst = fstElmnt
       .getElementsByTagName("nazwisko");
     Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
     NodeList lstNm = lstNmElmnt.getChildNodes();

      System.out.println("\n***");
     System.out.println("Atrybut plec: "
       + fstElmnt.getAttribute("plec"));
     System.out.println("Element Imię : "
       + ((Node) fstNm.item(0)).getNodeValue());
     System.out.println("Element Nazwisko : "
       + ((Node) lstNm.item(0)).getNodeValue());
    }

    }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}
SAX
Poznaliśmy już bardzo prostą metodę parsowania XML'i łającą pliki do pamięci operacyjnej komputera. Ale co jeśli mamy bardzo duży plik XML którego nie chcieli byśmy w całości wczytywać? W takim wypadku możemy użyć z SAX'a, czyli Simple API for XML. Określamy szereg metod, które wywołują się podczas parsowania pliku XML. Przetwarzanie metodą SAX jest jednokierunkowe.
Poniżej proste dwie klasy korzystające z SAX:
package com.blogspot.xml.sax;

import org.xml.sax.*;
import org.xml.sax.helpers.*;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
public class Handler extends DefaultHandler {

  @Override
 public void startElement(String namespaceURI, String localName,
   String qualifiedName, Attributes att) throws SAXException {
  System.out.println("Znalezione element: " + qualifiedName);
  if (qualifiedName.equals("employee")) {
   System.out.println("Znalezione atrybut: " + att.getValue("name"));
  }
 }

  @Override
 public void characters(char ch[], int start, int length)
   throws SAXException {

   System.out.println("Treść elementu: " + start + " to "
    + (start + length - 1) + ": " + new String(ch, start, length));
 }

}
package com.blogspot.xml.sax;

import javax.xml.parsers.*;
import org.xml.sax.XMLReader;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
public class Sample {

  public static void main(String args[]) throws Exception {

   // Tworzenie parsera
  SAXParserFactory spf = SAXParserFactory.newInstance();
  spf.setNamespaceAware(true);
  SAXParser saxParser = spf.newSAXParser();
  XMLReader parser = saxParser.getXMLReader();

   // Tworzenie klasy Handler
  Handler handler = new Handler();
  parser.setContentHandler(handler);

   // Zaczęćie parsowania dokumentu
  parser.parse("myFile.xml");
 }
}