29 января 2008

Админка на Jsp & Jstl

Создан небольшой пример, который позволит новичкам познакомится с технологиями написания web приложений на java.
Скачать можно тут.
Для работы с примером нам потребуется веб контейнер, например Tomcat6, который можно скачать с официального сайта Apache Tomcat.
После инсталяции Веб контейнера, установите war файл примера на сервер (deploy).
Данный пример состоит из трёх jsp файлов, а также двух вспомогательных классов:
index.jsp - главная страница, проводит авторизацию пользователей, только авторизованные пользователи получают доступ к нашей админке.
users.jsp - список пользователей, которые имеют доступ к админке, лишних пользователей можно удалить.
adduser.jsp - форма, где можно создать нового пользователя.
Список пользователей хранится в хмл файле users.xml. Каждый пользователь имеет свой логин и пароль.
По умолчанию существует пользователь с логином: "admin", пароль: "admin";
замечание! Это учебный пример, поэтому для наглядности реализована минимальная функциональность для корректной работы.
Знакомимся с примером и задаём вопросы, указываем на замечания.

25 января 2008

java.util LinkedList

Решил познакомится поближе с возможностями данного класса.
LinkedList - это реализация интерфейса List, которая реализует все операции списка и позволяет добавлять любые элементы (включая null).  Кроме реализации интерфейса List , LinkedList реализует методы получения, удаления и вставки в начало и конец списка. Такие операции позволяют использовать рассматриваемый класс как стек, очередь и двухсторонняя очередь.
Единственный негативный момент в том, что LinkedList является не синхронизированной. Тоесть при доступе к одному объекту LinkedList из нескольких потоков, необходимо, внешними средствами синхронизовать этот объект. Например создать объект, который будет инкапсулировать наш объект и отвечает за синхронизацию синхронизацию:
List list = Collections.synchronizedList(new LinkedList(...));

Так теперь перейдём к примерам.
1. Создание стека с помощью LinkedList :

import java.util.LinkedList;
public class MainClass {
  public static void main(String[] args) {
    StackL stack = new StackL();
    stack.push("First In");
    stack.push("Second In");
    System.out.println(stack.pop());
    System.out.println(stack.pop());
  }
}
class StackL {
  private LinkedList list = new LinkedList();
  public void push(Object v) {
    list.addFirst(v);
  }   public Object pop() {
    return list.removeFirst();
  }
}

Как известно стек работает по принципу FILO (first in last out), так что результат работы нашего примера:
>Second In
>First In


2. Создание очереди с помощью LinkedList:

import java.util.LinkedList ;
public class Queue {
  private LinkedList list = new LinkedList();
  public void put(Object v) {
   list.addFirst(v);
  }
  public Object get() {
    return list.removeLast();
  }
  public boolean isEmpty() {
    return list.isEmpty();
  }
  public static void main(String[] args) {
    Queue queue = new Queue();
    for(int i = 0; i < 10; i++)
      queue.put(Integer.toString(i));
    while(!queue.isEmpty())
      System.out.println(queue.get());
  }
}

В данном примере реализован принцип очереди: FIFO (first in first out).

Как вы заметили в этих примерах были ограничены возможности класса LinkedList, потому что он (LinkedList) имеет в своём арсенале методы реализующие и стек и очередь и двухсторонню очередь.

24 января 2008

Что выбрать в качестве базы данных PostgreSQL или MySQL

В следующей таблице приведены основные характеристики и возможности каждой из указанных бд.


POSTGRESQL

MYSQL

Совместимость с ANSI SQL стандартом

Очень близка к ANSI SQL стандарту

В некоторой мере совместима с ANSI SQL

Сравнительная производительность

Работает медленней

Работает быстрее

Под запросы

+

-

Транзакции

+

+

Репликация баз данных

+

+

Поддержка внешних ключей

+

-

Представления

+

-

Хранимые процедуры

+

-

Триггеры

+

-

Объеденения

+

-

Поддержка Windows

+

+

Очистка

+

-

Поддержка ODBC

+

+

Поддержка JDBC

+

+

Разные типы таблиц

-

+



Как видно из таблицы за счёт своей простоты, MySQL работает быстрее чем PostgreSQL. В большинстве случаев этой базовой функциональность MySQL вполне достаточно для разработки не слишком сложных Web приложений. Но всё же, PostgreSQL предоставляет много преимуществ для построение мощного хранилища и есть хорошей бесплатной альтернативой для Oracle, DB2 или MSSQL.
Так что при выборе базы данных для своего приложения необходимо внимательно оценить свои потребности и сделать правильный выбор.

ресурсы: 1 & 2

22 января 2008

Рекомендуемая литература по Java

Thinking in Java, 2nd Edition Russian version
Thinking in Patterns Russian version
Thinking in Enterprise Java Russian version
В оригинале эти книги можно найти на сайте http://www.mindview.net/Books

Ловкость рук и никакого мошенничества

16 января 2008

Отправка почты с помощью Java Mail через протокол SSL/TLS

Как использовать базовые функции Java Mail уже было расмотрено в одном из предыдущих обзоров. Теперь

рассмотрим, как отправлять почту через защищённое соеденение с smtp сервером.
для того, что-бы установить такое соеденение необходимо:
- принять сертификаты подлинности сервера;
- пройти аутентификацию на сервере.

Для начала мы должны зареестрировать провайдера алгоритма SSL :
Security.addProvider( new com.sun.net.ssl.internal.ssl.Provider());

Далее следует создать класс, который является наследником: SSLSocketFactory, и добавить имя этого класс в

свойства:
Security.setProperty( "ssl.SocketFactory.provider",SimpleSSLSocketFactory.class.getCanonicalName());

Для того что-бы выполнить соеденение по SSL/TLS нам надо принять все сертификаты сервера. Для этого мы

перегрузим свой TrustManager(класс проверяющий подлинность сертификатов) и при инициализации SSL сессии в

нашем SimpleSSLSocketFactory , TrustManager будет без проверки принимать все сертификаты предоставленные

сервером. Благодаря этому нам удастся установить соеденение с сервером.

Теперь нам осталось установить ещё несколько дополнительных свойств для использования SSL/TLS :

final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
props.setProperty( "mail.smtp.socketFactory.class", SSL_FACTORY);
// использовать только ssl соеденения в любом из направлений
props.setProperty( "mail.smtp.socketFactory.fallback", "false");
// smtp требует автентификации
props.setProperty("mail.smtp.auth","true");

После этого мы собираем письмо, как показано в предыдущей статье и отсылаем его следующим образом:
Transport tr = session.getTransport("smtp");
tr.connect(smtpHost, username, password);
msg.saveChanges();
tr.sendMessage(msg, msg.getAllRecipients());
tr.close();

Где в полях username, password надо указать соответствующие данные учётной записи на smtp сервере.

На этом всё. Если у вам не удалось самому собрать такое приложение, вы можете скачать мои исходники.
Ресурсы:
исходники : http://depositfiles.com/files/3109865
java.sun.com/products/javamail


15 января 2008

Отправка почты с помощью Java Mail

JavaMail API представляtn собой платформонизависимый фреймворк для создания приложений способных работать с почтовыми серверами.
JavaMail распостраняется как дополнительный пакет для J2se, а также он входит в J2ee sdk.
Если у вас не установлено J2ee sdk, то вы можете скачать java mail API из сайта Sun Microsistems : java.sun.com/products/javamail .
В данном примере мы разберём как отправлять простые письма с помощью Mail API, поетому из скачаного архива нам понадобится библиотека mail.jar.

Для отправки сообщений написали функцию, которая получает все необходимые параметры (адрес smtp , smtp порт, e-mail адресс с которого отправляю, e-mail адресс на который отправляют, тема письм и содержание).

public void send(String smtpHost, int smtpPort, String from,String to, String subject, String content) throws AddressException, MessagingException {

java.util.Properties props = System.getProperties();
props.setProperty("mail.smtp.host", smtpHost); props.setProperty("mail.smtp.port", ""+smtpPort);
Session session = Session.getDefaultInstance (props, null);
// Construct the message
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(from));
msg.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
msg.setSubject(subject);
msg.setText(content);
Transport.send(msg);
}

Вызов функции будет иметь приблизительно такой вид.
send("smtp_server.com", 25, " from@email.com","to@email.com", "title","Hello from app!");

Замечание. необходимо указывать рабочий smtp иначе будет генерироватся исключение.
В следующей части рассмотрим отправку сообщений с аутентификацией через защищённый протокол ssl.

12 января 2008

String в вопросах и ответах

1
Какая разница между:
String s1="string";
и
String s2=new String("string");

В первом примере создаётся только один объект строка: "string" , а затем создаётся указатель s1 на эту строку. Во втором примере сначала создаётся первый объект "string", а затем второй объект строка оператором new. В итоге получается второй способ менее эффективным.

2
Когда следует использовать String, а когда StringBuffer ?
Оба класса String и StringBuffer предназначены для работы со строковыми переменными, которые содержат более одного символа. Класс String следует использовать для работы со строками, значение которых не будет меняться. Например, если вы передаёте в метод строковый параметр, который точно не будет изменятся внутри метода, то лучше передавать строку с помощью класса String.
Класс StringBuffer следует использовать для строковых переменных, которые будут изменяться. Например когда считіваются данные из файла и динамически создаётся строковая переменная. Это связано с тем, что String - константа, и при каждом изменении будет создаватся новая строка и переприсваиватся указатель на неё.

3
Как преобразовать 16ричной число в виде строки "FFFA" в 10чную форму.
Можно использовать функцию: Integer.parseInt(String s,Int r);
r- базис (radix) в десятичной системе для 16чных чисел равен 16ти.

4
Есть String, которая состоит из нескольких строчек разделённых символом '\n' , как их объеденить ?
Можно использовать класс java.util.StringTokenizer. Например следующим образом:

StringTokenizer t=new StringTokenizer(" 1 \n 2 \n 3 \n 4 ","\n");
while (t.hasMoreTokens()){
System.out.println(t.nextToken());
}

5
Как проверить что введённая строка состоит ТОЛЬКО из заглавных символов?

String onlyLowerCase="SOME STRiNG";
if ( onlyLowerCase.equals(onlyLowerCase.toUpperCase())){
// в строке только заглавные символы ...
}

11 января 2008

Создание Web Сервиса на Java с помощью Tomcat и Jwsdp

Написание Веб сервиса - серверной и клиентской части будет состоять из 20 простых шагов. Но для начала необходимо выполнить кое - какую предварительную работу.

Первым делом устанавливаем Web Container, например: Tomcat6.
В переменных окружения создаём: CATALINA_HOME и TOMCAT_HOME, в обеих указываем пути к установленному каталогу.

Устанавливаем JWSDP (Java Web Service Developer Pack) и создаём переменную окружения: JWSDP_HOME.

Замечание! при написании web сервиса использовалось: jdk 1.5, tomcat 6.0, jwsdp 2.0 и дополнительно были обновлены библиотеки: saaj до версии 1.3 ( saaj.dev.java.net) при других версиях программ могут возникать ошибки работы ( о которых вы можете написать в коментариях).

Создаём приложение

В данном примере не будут использоватся никакие среды разработки (IDE), поетому создаём в нашей рабочей папке следующие кататлоги:
WS
- build
- config
- dist
- doc
- src
- web

Написание Серверной части

1. Создаём интерфейс веб сервиса, где объявляем методы, к которым может обращатся клиент

// сохраняем в src/server/wstest.java
package server;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.lang.*;
public interface wstest extends Remote {
public String getEchoString(String strv) throws RemoteException;
public int getEchoInt(int intv) throws RemoteException;
public int add (int i, int j) throws RemoteException;
public double divide (int i, int j) throws RemoteException;
}

2. Создаём класс где реализуем методы, описанные в интерфейсе
// сохраняем в src/server/wstestImpl.java
package server;
import java.lang.*;
public class wstestImpl implements wstest {
public String getEchoString(String strv) {

return strv;

}

public int getEchoInt(int intv) {

return intv;

}

public int add (int i, int j) {

return i+j;
}

public double divide (int i, int j) {

return (double)i/(double)j;

}
public static void main (String[] args){
wstestImpl wstest = new wstestImpl();

System.out.println(" 5+2 = "+wstest.add(5,2));
System.out.println (" 5/2 = "+wstest.divide(5,2));
}

}

3. Создаём конфигурационный файл веб сервиса
<?xml version="1.0" encoding="UTF-8"?>
<!-- configuration file for JWSDP wsdeploy tool -->
<webServices xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/dd" version="1.0"
targetNamespaceBase="http://peteryeung.homeip.net/targetNamespaceBase/operation/message " typeNamespaceBase="http://peteryeung.homeip.net/typeNamespaceBase/type "> <!-- the endpoint name becomes the service name in the WSDL --> <endpoint name="wstestService" interface="server.wstest" implementation="server.wstestImpl"/> <endpointMapping endpointName="wstestService" urlPattern="/wstestService"/> </webServices>

сохраняем в : config/ jaxrpc-ri.xml

4. Создаем web.xml файл

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>SimpleWebService</display-name> <description>First web service by me</description> <session-config> <session-timeout>60</session-timeout> </session-config> </web-app>

сохраняем в config/web.xml

5. Копируем библиотеки в каталог библиотек Tomcat (CATALINA_HOME\Lib) :

%JWSDP_HOME%\jaxrpc\lib
%JWSDP_HOME%\saaj\lib
%JWSDP_HOME%\jwsdp-shared\lib
%JWSDP_HOME%\jaxp\lib\endorsed
%JWSDP_HOME%\sjsxp\lib\
%JWSDP_HOME%\fastinfoset\lib\

Для пунктов 6 - 10 были созданы отдельные bat файлы, которые по очереди запускались

6. Компилируем исходники серверной части

javac -d build src/server/*.java

7. Создаём правильную структуру WAR архива

md web\WEB-INF
md web\WEB-INF\classes
xcopy/S build\server\* web\WEB-INF\classes\server\
copy config\jaxrpc-ri.xml web/WEB-INF
copy config\web.xml web/WEB-INF

8. Создаём WAR файл

jar -cvf build/myWEB-INF.war -C web\ .

9. Переделываем WAR архив специально для Web сервиса
md dist
md build\tmpdir
%JWSDP_HOME%\jaxrpc\bin\wsdeploy.bat -verbose -o dist/myWStest.war build/myWEB-INF.war

10. Загружаем на Tomcat
copy dist\myWStest.war %TOMCAT_HOME%\webapps

11. Перезагружаем Tomcat

12. Проверяем wsdl файл
http://localhost:8080/myWStest/wstestService?WSDL

Если всё ранее выполнено правильно , то откроется настроечный XML файл.

Создание клиенсткой части

13. Определяем для клиента, где находится сервис ( WSDL )

config/wscompile_config.xml

<?xml version="1.0"?>
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<!-- WSDL URL and generated package name --> <wsdl location=" http://localhost:8080/myWStest/wstestService?WSDL" packageName="clientStub"></wsdl> </configuration>

14. Генерируем код заглушки (stub code)
%JWSDP_HOME%\jaxrpc\bin\wscompile -d build -gen:client -keep config/wscompile_config.xml

15. Генерируем документацию (java docs)
javadoc -d doc\clientStub build\clientStub\*.java

16. Создаём Jar
md lib jar -cvf lib/wsstub.jar -C build clientStub/

17. Создаём тестовое клиент приложение
// сохраняем в src/client/wstestclient.java
import clientStub.*;

public class wstestclient {
public static void main (String[] args)
{

WstestService wstestService = new WstestService_Impl();

Wstest wstest=null; try { wstest = wstestService.getWstestPort();
}
catch(javax.xml.rpc.ServiceException e) { e.printStackTrace(System.err);
}
// Invoke the webservices
try {
System.out.println(" wstest.getEchoInt(1) -> "+wstest.getEchoInt(1));
System.out.println(" wstest।getEchoString(\"test\")->"+wstest.getEchoString("test"));
System.out.println(" 5+2 = "+wstest.add(5,2)); System.out.println(" 5/2 = "+wstest.divide(5,2));
}
catch (java.rmi.RemoteException e) {
e.printStackTrace (System.err);
}

}

}


18. Компилируем тестовый пример
javac -g -d build -classpath lib/wsstub.jar;
%JWSDP_HOME%\jaxrpc\lib\jaxrpc-api.jar;
%JWSDP_HOME%\jaxrpc\lib\jaxrpc- spi.jar;
%JWSDP_HOME%\jaxrpc\lib\jaxrpc-impl.jar;
src/client/*.java


19. Запускаем клиент
java -cp lib/wsstub.jar;
%JWSDP_HOME%\jaxrpc\lib\jaxrpc-api.jar;
%JWSDP_HOME%\jaxrpc\lib\jaxrpc- spi.jar;

%JWSDP_HOME%\jaxrpc\lib\jaxrpc-impl.jar;

%JWSDP_HOME%\jwsdp-shared\lib\jax-qname.jar;
%JWSDP_HOME%\jwsdp-shared\lib\activation.jar;
%JWSDP_HOME%\jwsdp-shared\lib\mail.jar;

%JWSDP_HOME%\saaj\lib\saaj- impl.jar;
%JWSDP_HOME%\saaj\lib\saaj-api.jar;
%JWSDP_HOME%\jaxp\lib\endorsed\xercesImpl.jar; %JWSDP_HOME%\fastinfoset\lib\FastInfoset.jar;
%JWSDP_HOME%\sjsxp\lib\jsr173_api.jar;
%JWSDP_HOME%\jaxp\lib\endorsed\dom.jar;
build client.wstestclient pause


20. Результат работы появится в консоли
wstest।getEchoInt(1) -> 1
wstest।getEchoString("test") -> test
5+2 = 7
5/2 = 2.5

создание Web сервиса успешно завершено

Настройка Apache Tomcat для работы с протоколом SSL

SSL (Secure Socket Layer) - это технология, которая позволяет устанавливать бзопасное соеденение между веб броузером и веб сервером. Это значит что каждая из сторон будет отправлять данные в зашифрованном виде, а другая сторона будет их расшифровывать перед обработкой. Второй важный аспект в работе протокола SSL - это аутентификация. Прежде чем расказать серверу свои секретные данные (логин, пароль) сервер предоставит униальный "Сертификат" - доказательства того, что этот сервер действительно тот за кого себя выдаёт . Так же возможны случаи, когда сервер запрашивает "сертификат" у броузера клиента - "Клиентская аутентификация".

От теории к практики. Для начала нам необходимо сгенерировать сертификат для Apach Tomcat. В этой задаче нам поможет утилита keytool. В более ранние версии J2se она невходила и приходилось качать дополнительный пакет JSSE (java SE security) , но начиная с j2se 1.4 такой необходимости нету.
Итак, для генерации сертификатов, необходимо запустить утилиту keytool.
В Windows:
%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA
в Unix:
$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA

После запуска вам будет предложен ряд вопросов, ответив на которые вы сгенерируете сертификат.
Внимание. Это всего лишь тестовый сертификат, который может использоватся для разработки и тестирования приложений, в реальных бизнес приложениях сертифиаты должны быть выданы специальными ЦСК (центр сертификации ключей), которые несут ответственность за их автентичность.

Сертификат сгенерирован, осталось разрешить томкату принимать SSL соеденения. Для этого в файле $CATALINA_HOME/conf/server.xml неоходимо раскоментировать запись:"SSL HTTP/1.1 Connector", где указывается параметры соеденения, у меня она выглядит следующим образом:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" />
Протестировать SSL можно:
https://localhost:8443
Броузер проинформирует о наличии на сервере сертификата от неизвестной организации и предложит принять его, что и надо сделать для загрузки страници.

Парсинг XML с помощью DOM

Пусть у нас имеется xml файл в котором хранится список студентов.
<students>
<student>
  <name>Nikolaj</name>
  <surname>Ivanov</surname>
  <age>23</age>
  <group>PF-11</group>
</student>
<student>
  <name>Petr</name>
  <surname>Kilkin</surname>
  <age>22</age>
  <group>FP-22</group>
</student>
</students>
перед нами стоит задача извлечь данные о студентах в список (например ArrayList) для дальнейшей обработки.
Первое что сделаем - напишем класс, который будет описывать студента:
class Student{
private String name="";
private String surname="";
private int age="";
private String group="";
// самостоятельно добавьте конструктор, а также
// getXXX() и setXXX() методы для каждого параметра
}

Теперь переходим к написанию парсера. Основной идеей Dom парсера есть перебор по дереву всех элементов хмл файла. Наш класс - парсер будет читать хмл файл и выбирать все необходимые данные оттуда. Сразу приведу пример такого класса:


//Dom Parser
import java.util.*;
import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;

public class DomStudParser
{
private Document doc = null;
private String txt = "";
private Student tmpS = null;
private List stds = null;

// fName - имя хмл файла
public DomHostsParser(String fName)
{
  try
  {
   doc = parserXML(new File(fName));
   stds = new ArrayList();
   visit(doc, 0);
   Host tmp=null;
  }
  catch(Exception error)
  {
   error.printStackTrace();
  }
}

public void visit(Node node, int level)
{
  NodeList nl = node.getChildNodes();  
  String parent="";
  for(int i=0, cnt=nl.getLength(); i<cnt; i++)
  {  
   if (nl.item(i).getNodeType()==Node.TEXT_NODE){ // if1
    parent=nl.item(i).getParentNode().getNodeName();
    txt=nl.item(i).getNodeValue();
    if (parent=="name"){ // if1.1
     tmpS.setName(txt);
    }
    if (parent=="surname"){ // if1.2
     tmpS.setSurname(txt);
    }
    if (parent=="age"){  // if1.3
     tmpS.setAge(Integer.valueOf(txt));
    }
    if (parent=="group"){
     tmpS.setGroup(txt);
    }
   } else {
    if (nl.item(i).getNodeName().equals("student")){
     tmpS=new Student();
     stds.add(tmpS);
    }
   }
   System.out.println(nl.item(i).getNodeName() + " = " + nl.item(i).getNodeValue());
   visit(nl.item(i), level+1);
  }
}
public Document parserXML(File file) throws SAXException, IOException, ParserConfigurationException
{
  return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file);
}
public List getStds() {
  return stds;
}
public void setStds(List stds) {
  this.stds = stds;
}
}

Итак немного объяснений.
Функция parserXML преобразовывает наш хмл файл в хмл документ, над которым может проводить работу.
Основной в данном классе - рекурсивно вызываемый метод visit, который по дереву (поиск в глубину) перебирает все узлы нашего хмл елемента.
Узлы бывают нескольких типов: название атрибута, название элемента, значение элемента, коментарий и т.д.
В нашем случае узлы только 2х типов - это TEXT_NODE (значение элемента) и ELEMENT_NODE (название элемента). Парсер начинает просмотр с элемента "<students>" , далее обработке подвергнется "текст", который находится между тегами <students> и <student> , далее элемент <student> , при достижении которого сработает условие "else if" и будет создан новый экземпляр класса Student, который мы начнём заполнять. Когда дойдём до текста после элемента <name> - "Nikolaj" , сработает условие if1.1.Это произойдт потому что родителем для данного текста есть элемент name и т.д. мы переберём все элементы и в итоге получим List с двумя объектами Student внутри, получить этот список можна с помощью функции getStds().

подробнее:
http://java.sun.com/j2se/1.4.2/docs/api/org/w3c/dom/package-summary.html

10 января 2008

Как получить текущее время/дату

Существует множество способов для получение текущих времени/даты, всё зависит от того, для каких целей это нам нужно.
1. Мы хотим подсчитать время выполнения какого то метода. Для этого достаточно вызвать: System.currentTimeMillis () до и после выполнения метода.
Каждый вызов даст нам число - текущее время в милисекундах. Отняв второе от первого получим время работы метода в милисекундах.
2. Нам надо в правильно отформатированном виде вывести дату время.
В пакете java.util есть класс Calendar, которым мы и воспользуемся:
java.util.Calendar.getInstance().getTime()
результат стандартно сформированная строка, например:
Thu Jan 10 16:08:49 EET 2008
Если данный вид нас не устраивает, можно использовать класс SimpleDateFormat из пакета java.text , он предоставляет гораздо более широкие возможности в отображении даты / времени.
Например
String dt=new java.text.SimpleDateFormat("dd-MMM-yy G hh:mm aaa")).format(java.util.Calendar.getInstance ().getTime();

даст нам результат в виде :
10-янв-08 н.э. 04:08 PM
Полный перечень ключевых слов, которые могут быть использованны при формирования вида отображения даты/времени можно узреть в документации Sun : SimpleDateFormat

05 января 2008

Пределы примитивных типов данных

Небольшая програмка, которая выводит пределы для примитивных типов данных.

class PrimitivLimits{
public static void main(String []s){
System.out.println("Byte: [" + Byte.MIN_VALUE + "," + Byte.MAX_VALUE +"]");

System.out.println("Short: ["+Short.MIN_VALUE+" , " + Short.MAX_VALUE+"]");

System.out.println("Int: ["+Integer.MIN_VALUE+" , " + Integer.MAX_VALUE+"]");
System.out.println("Long: ["+Long.MIN_VALUE+" , " + Long.MAX_VALUE+"]");
System.out.println("Float: ["+Float.MIN_VALUE+" , " + Float.MAX_VALUE+"]");
System.out.println("Double: ["+Double.MIN_VALUE+" , " + Double.MAX_VALUE+"]");
}
}

01 января 2008

Алгоритм Des. Симметрическое шифрование в java

Симметрическое шифрование - способ шифрования, в котором для (за)шифрования и расшифрования применяется один и тот же криптографический ключ.
Рассмотрим реализацию симметрического шифрования в java на примере алгоритма DES. В первую очередь нам понадобится класс javax.crypto.Cipher , который реализует базовые функции популярных криптографических алгоритомов шифрования. Для создания экземпляра такого класса используется статистический метод Cipher.getInstance , который в качестве параметра получает имя криптографического алгоритма шифрования. В нашем случае:

Cipher chr = Cipher.getInstance("DES");

Следующим шагом будет инициализация экземпляра класса и указание каком режиме он будет работать:
в режиме шифрования chr.init(Cipher.ENCRYPT_MODE, key); - , или расщифрования -
chr.init(Cipher.DECRYPT_MODE, key); .

Как видно, появился новый неизвесный параметр: key - это 56 битный ключ алгоритма DES. Данный параметр имеет тип javax.crypto.SecretKey и может быть создан с помощью класса

javax.crypto.KeyGenerator.
SecretKey key = KeyGenerator.getInstance("DES").generateKey();

Шифрование или расшифрование выполняет функция doFinal класса Cipher, которая на входе получает масив байт и возвращает также масив байт, но уже соответственно преобразованных. Что именно (шифрование или расшифрование) будет выполнять функция зависит от того что было указанно в первом параметре функции инициализации init().

Итак из всего выше сказанного можно скомпоновать небольшой класс. Класс по работе скриптографическим алгоритмом шифрования DES. К классу прилагается функция main, для того что-бы проверить правильностб работы созданных функций.


import javax.crypto.*;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
* Класс реализующий работу с алгоритмом шифрования DES
* @author Rumoku
*/
class DesEncrypter {
Cipher ecipher;
Cipher dcipher;

/**
* Конструктор
* @param key секретный ключ алгоритма DES. Экземпляр класса SecretKey
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
*/
public DesEncrypter(SecretKey key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
ecipher = Cipher.getInstance("DES");
dcipher = Cipher.getInstance("DES");
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
}

/**
* Функция шифровнаия
* @param str строка открытого текста
* @return зашифрованная строка в формате Base64
*/
public String encrypt(String str) throws UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
byte[] utf8 = str.getBytes("UTF8");
byte[] enc = ecipher.doFinal(utf8);
return new sun.misc.BASE64Encoder().encode(enc);
}

/**
* Функция расшифрования
* @param str зашифрованная строка в формате Base64
* @return расшифрованная строка
*/
public String decrypt(String str) throws IOException, IllegalBlockSizeException, BadPaddingException {
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
byte[] utf8 = dcipher.doFinal(dec);
return new String(utf8, "UTF8");
}
/**
* Функция для проверки правильности работі класса
*/
public static void main(String[] s) throws IllegalBlockSizeException, BadPaddingException, IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException{
SecretKey key=null;
key = KeyGenerator.getInstance("DES").generateKey();
DesEncrypter encrypter = new DesEncrypter(key);
String OStr1="simple string";
String SStr = encrypter.encrypt(OStr1);
String OStr2 = encrypter.decrypt(SStr);
System.out.println("Open String:"+OStr1+
"\nAfter encripting: "+SStr+"\nAfter decripting: "+OStr2);
}
}




Подключение к MySQL с помощью Jdbc

Для начала рассмотрим список того что нам надо:
1. MySQL сервер, причём он должен быть запущен.
2. JDBC connector для MySQL, можно скачать с оффициального сайта MySQL (dev.mysql.com ).
3. Собственно java sdk.

Итак, Вы скачали всё необходимое, приступаем к работе.
Мы не будем рассматривать процесс установки и настройки MySQL сервера, но для дальнейшей работы нам необходимо что - бы:
- MySQL сервер был запущен;
- сущестовал пользователь root без пароля (настройки по умолчанию);
- существовала база данных test.

Допустим всё указанное выполено, и переходим к настройкам jdbc. Сначала разархивируйте mysql драйвер например в каталог: "c:\mysql- JDBC-3.0.17\". (Во время написания статьи была именно эта (3.0.17) версия jdbc драйвера, у Вас может быть более новая.)
В корне архива лежит файл: "c:\mysql-JDBC-3.0.17\mysql-connector
-java-3.0.17-ga-bin.jar" , дальнейшая работа будет производиться именно с ним.

Создадим тестовый пример:

/* файл Connect.java */
import java.io.*;
import java.sql.*;
public class Connect
{
public static void main (String[] args)
{
Connection conn = null;
try
{
String userName = "root";
String password = "";
String url = "jdbc:mysql://localhost/test";
Class.forName ("com.mysql.jdbc.Driver").newInstance ();
conn = DriverManager.getConnection (url, userName, password);
System.out.println ("Database connection established");
}
catch (Exception e)
{
System.err.println ("Cannot connect to database server");
e.printStackTrace();
}
finally
{
if (conn != null)
{
try
{
conn.close ();
System.out.println ("Database connection terminated");
}
catch (Exception e) { }
}
}
}
}
/*конец файла*/


Немного объяснений.

String userName = "root";

String password = "";

имя пользователя в СУБД MySQL и его пароль. Этого пользователя создавать не надо, он существует в MySQL при установке.

String url = "jdbc:mysql://localhost/test";


Строка, подключения к бд, тут указывается что у нас локальный сервер MySQL (localhost) и база данных называется test.

Class.forName ("com.mysql.jdbc.Driver").newInstance ();


Инициализация драйвера jdbc для работы с MySQL.
В функию соеденения с бд getConnection() мы передаём все эти 3 параметра, и подключаемся к БД.
Замечание. Можно было не использовать отдельно имя пользователя и пароль, а создать строку подключение к БД следующего характера:

String url = "jdbc:mysql://localhost/[DB_Name]?user=[UserName]&password=[Password]";


Тогда функция соеденения с БД getConnection получала только один параметр, строку подключения.

conn.close ();


После завершения работы отключаемся от БД.

Замечание! Это всего лишь тестовый пример для того, что-бы научится подключать jdbc, в дальнейшем рекомендуется создать отдельный класс или покрайне мере функцию, которая будет получать как параметр настройки соеденения, и возвращать экземпляр класса Connection.

Компилируем и запускаем.

Не забываем, что для запуска необходимо подключить библиотеку mysql-connector-java-[version]-ga-bin.jar, или прописать её в переменную classpath, если вы не используете IDE.

Сокеты

Сокеты позволяют реализовать клиент серверную архитектуру клиент - сервер.
Клиент, подключается к определённому порту сервера зная его имя или IP адрес. Большинство сетевых программ построенны именно на этой архитектуре. Рассмотрим как это реализуется в Java с помощью сокетов.
Итак, начнём с рассмотрения создания сокет сервера. Его основная задача: принимать входящие соеденения на какой то зарание определённый порт. Это реализуется с помощью класса java.net.ServerSocket. Следующий кусок кода отвечает за открытие порта №5000 на текущем компьютере (сервере) и приёме входящих подключений к серверу и создание экземпляра класса java.net.Socket для дальнейшей работы с подключённым клиентом.

try {
int port = 5000;
ServerSocket srv = new ServerSocket(port);
Socket socket = srv.accept();
} catch (IOException e) { }

Ну что ж сервер мы написали, следующий этап - написание клиента - программы которая будет подключатся к серверу. Номер порта сервера нам известен - №5000, в учебных целях клиент и сервер будем запускать на одном компьютере, тогда в качестве имени хоста можна использовать ключевое слово : localhost или IP адрес 127.0.0.1

try {
InetAddress addr = InetAddress.getByName("localhost");
int port = 5000;
Socket socket = new Socket(addr, port);
} catch (UnknownHostException e) {
} catch (IOException e) { }

Итак, на клиенте мы просто создаём новый сокет с указанными параметрами, если в момент запуска клиента сервер уже будет работать, значит подключение пройдёт успешно, без генерации исключений и мы сможем отправлять и получать данные.
В итоге мы имеем два работающих Socket, один на программе - сервере, второй на программе - клиенте. Реализуем возможность клиентом отправлять на сервер некую строку данных , а серверу получать её, обрабатывать и выводить в консоль, тогда на сервере надо создать экземпляр класса java.io.BufferedReader :

try {
BufferedReader rd = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str;
while ((str = rd.readLine()) != null) {
System.out.println(str);
}
rd.close ();
} catch (IOException e) { }

который прослушивает сокет и выводит на экран текст из потока ввода, до тех пор, пока из потока ввода поступают данные. На клиенте мы создадим экземпляр класса java.io.BufferedWriter, который будет передавать полученный текст в сокет:

try {
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
wr.write("Hello server");
wr.flush();
} catch (IOException e) {
}

В результате мы получили примитивное но вполне рабочее клиент - серверное приложение, которое способно обмениватся данными.