31 октября 2008

Лучший Java Web фреймворк


В комментариях можно писать свой вариант.

DarkStar: разарботка MMORG ( онлайн игр ) на Java

Проект Darkstar это программное обеспечение, которое призвано упростить разработку и эксплуатацию массово масштабируемых онлайн игр(MMORG), виртуальных миров, и социальных сетей. Darkstar сам позаботиться об организации связей , обработке событий, слежением за целосностью данных и многое другое. Использование Darkstar вам позволит сконцентрироватся непосредственно на разработке игры.
И теперь главный плюс - это опен сорс проект, под GPL лицензией, так что вы можете получить его бесплатно. С использованием этого SDK разработка вашей игры может ускорится во много раз.

Так, расскажу немного о внутренностях. В целом это стандартный клиент сервер, который берёт на себя задачу управления. Основное понятие используемое в Darkstar проекте - это задача - Task. Любое действие можно описать с помощью задачи. Пример:
Атака (один игрок атакует - наносит удар другому игроку).
Итак происходит обращение к Task менеджеру с вызовом соотвующей задачи с указанными параметрами. TaskManager в свою очередь лезет в базу данных достаёт необходимые параметры (количество жизни у врага, мощность брони; мощность, ти оружия и т.д.) - за работу с базой данных отвечает PersistanceManager. На основе извлечённых данных производиться рассчёт силы удара и результат - нанесённое повреждение: опять обращение к PersistanceManager и сохранение в БД. Осталось разослать эту информацию игрокам участвующим в схватке - не проблема - TaskManager обращается к ChanelManagerу и обновлённые данные получают все игроки. Итак три слона держащие мир Darkstar это TaskManager , PersistanceManager и ChanelManagerу , можно и свой написать, но это только в очень искушённых проектах.
Подробности на сайте сообщества. Там много примеров, хорошая документация и всё что нужно для разработки.

Try it now.

Links:
About
Project Darkstar community

25 октября 2008

Java презентации

Обнаружил тучу Java презентаций на сайте parleys.com . В презентациях охватывается большинство тем связанных с javа : от fundamentals до java ee фреймворков.
Взяты презентации из популярнейших Java конференций : JavaPolis, BeJUG, SpringOne, JaZoon, JavaZone and EclipseCon

У сайта есть также свой подкаст : parleys.libsyn.com где можно прослушать доклады по презентациям в mp3 формате.

Наслаждайтесь.

P.S. Всё оформлено очень красиво и по взрослому: в одном окне слайды презентации , во втором видно докладчика...как будто сам присутствуешь на конференции. Особенно удобное их десктоп приложение, которое скачивается на этом же сайте.

JAD : Java декомпилятор

Jad - java декомпилятор, программа которая читает один или больше Javaклассов и преобразует их в исходный код(по личной практике сообщу, чтокод получается почти такой же как и до компиляции), который можно будетповторно скомпилировать.
Jad написан на чистом С++, поэтому работает в несколько раз быстрее чем декомпиляторы написаны на Java.
Использовать просто:

jad example1.class

Но , jad по умолчанию выдает декомпилированным файлам расширение jad, что бы избежать этого , можно использовать опцию -s :

jad -sjava example1.class


Если надо декомпилировать набор классов, можно воспользоваться командой:

jad -o -r -sjava -dsrc tree/**/*.class


(**) - значит что декомпиляция будет производиться во всех поддиректориях папки tree.

JAD

20 октября 2008

Spring Security : хранение пользователей в БД. часть 2

Предварительно прочитать:
SS: хранение пользователей в БД. часть 1
В этой части мы рассмотрим возможность объеденения ORM фреймворка (например hibernate) вместе со Spring Security. При этом будут использоваться аннотации.
Итак, lets go.
Если вы желаете хранить пользователей в своих таблицах, а не предлагаемых SS-ом и желаете обращатся к ним с помощью hibernate? тогда вам надо:

1) Реализовать интерфейс UserDetailsService, в котором аж одна функция loadUserByUsername. У меня этот интерфейс обращается к моим dao классам , с помощью которых и извлекает информацию о пользователях, например:
@Component
@Transactional
public class UserServiceImpl implements UserDetailsService {
    @Autowired
    UserDao userDao;
    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException, DataAccessException {         
        return userDao.get(username);
    }
}


Особенность, обратите внимание , что функция loadUserByUsername возвращает не абы-шо , а некий объект UserDetails. Это между прочим тоже интерфейс.

2) Реализовать интерфейс UserDetails. SS рекомендует воспользоватся стандартным классом org.springframework.security.userdetails.User , в котором уже реализован этот интерфейс, но этот вариант далеко не всем подойдёт.
Если таки не подойдёт, надо реализовать несколько простых стандартных функций не представляющих большой интерес, аля: getUsername, getPassword, isEnabled, isCredentialsNonExpired, isCredentialsNonExpired, isAccountNonExpired. Причём последние 4 возвращают ложь или правду. Гораздо интересней функция getAuthorities(), а точнее то что она возвращает, а возвращает она массив GrantedAuthority... это между прочим тоже интерфейс, который нам придётся реализовывать :).

3) Реализовать интерфейс GrantedAuthority. Что это за интерфейс , и что это за единственная функция getAuthority() , которую надо реализовать? GrantedAuthority - это привилегия, роль, полномочие, ограничение которое получает пользователь на выполнение того или иного действия. Как задавать набор действий для каждой определённой роли в общем рассматривалось в первой заметке по SS , и более подробно будет рассматриватся в дальнейшем.
Основные используемые роли :
ROLE_ADMINISTRATOR, ROLE_USER, ROLE_SUPERVISOR, ROLE_WE_DONT_HAVE, ROLE_TELLER, ROLE_ANONYMOUS
Каждый пользователь может обладать не менее чем одной ролью. Поэтому в бд лучше всего иметь одну таблицу для данных пользователя и вторую для ролей. Первая таблица связана со второй в отношении один ко многим.

4) Последний штрих. Все классы написаны, осталось только настроить конфигурацию, для того, что-бы использовался нужный сервис получения пользователей. Это можно сделать в applicationContext-security.xml сделующим образом:
Регистрируем бин с классом реализующем UserDetailsService интерфейс:

    <beans:bean id="myUserDetailsService" class="path.to.UserServiceImpl" />   

В authentication-provider указываем какой сервис использовать для получения данных о пользователях:

    <authentication-provider user-service-ref='myUserDetailsService'/>

  Это всё.

Spring Security : хранение пользователей в БД. часть 1

В предыдущей заметке по Spring Security (SS) я рассмотрел пример использования SS. Пример был примитивный, ориентированный исключительно на знакомство с SS.
Теперь более подробно рассмотрим вопрос хранения данных о пользователях. В первом примере эти данные были забиты раз и навсегда в xml файл и как либо оперировать ними было невероятно трудно. Более привычный способ хранения пользователей - это база данных.
В SS реализован UserDetailsService, который позволяет получать информацию о пользователях посредством jdbc подключения к базе данных, для этого достаточно в конфигурации зарегистировать бин:
<bean id="userDetailsService" class="org.springframework.security.userdetails.jdbc.JdbcDaoImpl">
  <property name="dataSource" ref="dataSource"/>
</bean> 
 

Где в качестве dataSource используется бин настроек подключения к бд, например:
   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
  <property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
  <property name="username" value="sa"/>
  <property name="password" value=""/>
</bean>


При это в базе данных должна существовать следующая схема: таблицы users и authorities, а также внешний ключ.
  CREATE TABLE users (
  username VARCHAR(50) NOT NULL PRIMARY KEY,
  password VARCHAR(50) NOT NULL,
  enabled BIT NOT NULL
  );
 
  CREATE TABLE authorities (
  username VARCHAR(50) NOT NULL,
  authority VARCHAR(50) NOT NULL
  );
 
  ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users(username);

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

18 октября 2008

Опрос. Какие технологии вас интересуют больше всего?



Пример использования Spring Security в Web приложениях


Вступление


Не так давно Spring анонсировала свою новую разработку Spring Security. Это модуль для услуг безопасности, который должен заменить Acegi Security для всех Spring приложений.
Acegi очень популярный фреймворк для безопасности, обладающий обширной функциональностью:
- аутентификация и авторизация пользователей
- контроль доступа
Spring Security унаследовало всё лучшее от Acegi, а также обзавелось новыми фичами(features) :
- совместимость с OpenID, NTLM, LDAP аутентификация;
- поддержка аннотаций согласно стандарту JSR-250;
- упрощения в использовании;
- поддержка дополнительных языков;
и многие другие.

Пример

Что бы показать на сколько просто использовать Spring Security рассмотрим простой пример.
Для начала вам понадобиться любое простое Spring MVC веб приложение. В одном из более ранних постов я приводил примеры туториалов. Хотя, идеальной подойдёт пример petclinic , который поставляется в zip архиве spring-framework with dependencies.
Также нам понадобиться zip архив Spring Security 2.0.X , а точнее библиотеки из него.
Из которого надо в WEB-INF\lib скопировать следующие библиотеки:
spring-security-core-2.0.4.jar
spring-security-core-tiger-2.0.4.jar
spring-security-acl-2.0.4.jar
spring-security-taglibs-2.0.4.jar

И ещё одна библиотека от apache:
commons-codec-1.3.jar

Ещё необходимо создать конфигурационный файл для Spring Security в папке WEB-INF :
<!-- applicationContext-security.xml -->
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
<!-- alot of config will be here -->
</beans:beans>


Шаг следующий - настройка web.xml , где мы должны подключить конфиг для Spring Security:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>

Здесь же в web.xml сразу после закрытия тега /context-param добавляем фильтр:

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

И последний шаг - настраиваем доступ к страницам, указываем для SpringSecurity на какие странице можно заходить анонимно, а на которые доступ получат только авторизированные пользователи. Добавляем в aplicationContext-security.xml следующий код:
<http auto-config="true">
<intercept-url pattern="/*.do" access="ROLE_USER" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
</http>

В этом же файле создадим парочку пользователей:
<authentication-provider>
<password-encoder hash="md5"/>
<user-service>
<user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
<user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
</user-service>
</authentication-provider>

Можно тестировать. Запускаем сервер и пытаемся открыть домашнюю страницу, ваш запрос должен быть перехвачен и вместо данных вывестись форма с предложением ввести свои данные. Вы можете попробовать ввести
логин: rod , пароль: koala
либо
логин: dianne , пароль: emu
и увидеть ожидаемую страницу.
Ещё не помешает добавить кнопку для выхода из аккаунта, лучше всего в шаблон, например в header :
<table class="header">
<tr>
<td><a href="<c:url value="/welcome.do"/>">Home</a></td>
<td align="right"><a href="<c:url value="/j_spring_security_logout"/>">Logout</a></td>
</tr>
</table>

Оригинал: статья 1 , статья 2.

17 октября 2008

Open Source - сборники народных сказок

Решил поискать в истории некоторые аналоги для "open source" и os сообщества. И такой аналог нашёлся - народный фольклор: песни, танцы, музыка, притчи, истории, баллады и многое другое то что народ копил многие годы, передавая от родителей к детям. И творили люди свои шедевры не за деньги, а потому что им по настоящему нравилось то что они делают. Гениальные произведения мало вероятно, что удастся найти среди народных, но много хорошего, приятного для души очень много. Хорошо что кроме творящих ещё находятся люди, которые собирают эти произведения воедино, только благодаря ним к нам доходят сборники сказок, притч, песен ... творчества народа.

В опен сорсе наблюдается кое что аналогичное, только вот слово народ заменили более модным "комьюнити". А сборники народного творчества в опен сорсе пользуются особой популярностью. И что-бы некоторым пост не показался абсолютно бесполезным, размещу ка я ссылки на такие народные опен-сорс сборники:

http://sourceforge.net/
http://koders.com/
http://code.google.com/
http://java2s.com/
http://java-source.net/
http://www.exampledepot.com/
http://www.planet-source-code.com/
http://www.codebeach.com/
http://www.osalt.com/

Ну, думаю достаточно.

P.S. Жаль только что в список не попал не один славянский сайт, хоть люди у нас далеко не последние творят , а получается как и с народным фольклором - за-рубежом считается что русская народная музыка - это хор Красной армии.

16 октября 2008

Бесплатные тесты от Sun по Java

The following pre-assessments will assist you in determining whether you have acquired the knowledge taught in each of the Sun Microsystems' training courses listed below each pre-assessment. Sun offers each free pre-assessment to help you determine which course is best suited to your current level of skill and knowledge.

15 октября 2008

Динамический HTML список c использованием jQuery библиотеки


Допустим есть у вас html список (или таблица) с несколькими элементами , например:

<ul id="list_cheloveg">

<li id="174">
    <a class="link_cheloveg" href="read.html?id=174">Andrej Vanjiradjan1</a>
    <a class="dialog_edit" href="edit.html?id=174">Edit</a>
    <a class="delete" href="delete.html?id=174">Del</a>
</li>

<li id="175">
    <a class="link_cheloveg" href="read.html?id=175">Andrej Vanjiradjan2</a>
    <a class="dialog_edit" href="edit.html?id=175">Edit</a>
    <a class="delete" href="delete.html?id=175">Del</a>
</li>

<li id="176">
    <a class="link_cheloveg" href="read.html?id=176">Andrej Vanjiradjan3</a>
    <a class="dialog_edit" href="edit.html?id=176">Edit</a>
    <a class="delete" href="delete.html?id=176">Del</a>
</li>
</ul>


И вам надо добавить в конец ещё один элемент , либо отредактировать какой то из существующих. Найболее часто такая задача встречается при отправке запросов через Ajax, и ответ как раз и должен обновить таблицу.

Из 10 статей найденых в гугл, 9 предлагают использувать функцию getElementById, и с помощью неё установить HTML код конкретного элемента, например:

document.getElementById("176").innerHTML = '<li id=177> <a class . и т.д. копи пастим весь html c новыми атрибутоами.. </a></li>';

способ достаточно простой, но очень не красивый, тем более если это не список, а таблица в которой больше 10 столбиков.
Библиотека jQuery, позволяет эту задачу выполнить гораздо элегантней.

Шаг 1. скачиваем библиотеку и подключаем к странице:

<script type="text/javascript" src="jquery.js"></script>

Шаг 2.пишем javascript функцию, которая будет получать новые аттрибуты, обрабатывать их и обновлять таблицу.
Например, в моём случае список - это люди: уникальный id, имя и фамилия:

<script type="text/javascript">
function updateList(id,firstName,lastName) {
    var oldId   = $('#list_cheloveg li').attr('id');
    var oldText = $('#list_cheloveg li:last .link_cheloveg').text();
    var oldHtml = $('#list_cheloveg li:last').html();
    for (i=0;i<3;i++) { // id used 3 times in row    
        oldHtml = oldHtml.replace(''+oldId,''+id);
    }
    oldHtml = oldHtml.replace(oldText,firstName + ' ' + lastName);
    var newHtml = '<li id=' + id + '>' + oldHtml + '</li>';    
     if ( document.getElementById(id) == null ) {         
        $('#list_cheloveg').append(newHtml);
    } else {
        document.getElementById(id).innerHTML=newHtml;
    }
}
</script>

Что же делает эта функция? Она выбирает последнюю строку(последниц элемент списка) из таблицы,
создаёт 3 переменных, в которых сохраняет уникальный id, имя+фамилию , и старый html код который мы будем редактировать.
Панализировав список, можно увидеть, что нам надо заменить 3 раза уникальный id и один раз имя+фамилия. Это мы и сделали с помощью стандартной функции replace. Далле мы проверяем весь документ и исчем запись с новым id , если не находим, значит добавляем элемент в конец списка, как новую строку, если находим значит заменяем его.

Протестировать єтот пример можно с помощью двух ссылок:

<a href=# onclick="updateList(194,'textA','textB');">add</a>
<a href=# onclick="updateList(174,'textAA','textBB');">update</a>

P.s. Если скопируете весь html код из этого сообщения в один файл , и сохраните его в какую то  папку, и в эту же папку добавите jQuery библиотеку jquery.js , то сможете успешно протестировать то что я описал в посте.

Получение в Java коде номер строки и имя выполняемого файла

Во время отладки приложения наиболее часто используется вывод с помощью System.out.println(). Иногда, приходиться добавлять достаточно большое количество таких выводов, что бы понять процесс выполнения приложения и для каждого из выводов надо придумывать свой уникальный текст, что бы потом по тексту найти нужное место в коде.
А что если выводить на экран имя файла, метода и номер строки который в данный момент выполняется. Это автоматически обеспечит уникальные сообщения для каждого вывода System.out ,  а также позволит легко и быстро размножать такие выводы в коде. Вывод будет выглядеть приблизительно так:

System.out.println(getCodePoint());

Но самое интересное будет происходить в методе getCodePoint его можно сделать общим и статическим в каком то классе утилит , содержимое его будет следующим:

public static String getCodePoint() {
    StackTraceElement ste = Thread.currentThread().getStackTrace()[2];
    return ste.getFileName() + ":" +
           ste.getClassName() + ":" +
           ste.getMethodName() + ":" + 
           ste.getLineNumber();
}


Магия и ничего более :).

14 октября 2008

Как получить состояние любого локального / удалённого java процесса

Данная задача является особенно актуальной для серверной части, где у вас на одной машине может в фоновом режиме выполнятся несколько Java процессов.
Для того что бы определить как выполняется определённый процесс надо знать его pid (process Id). Вы можете получить его из диспечера задач (в windows) , команд ps или top в линуксе, но поиски этим методом могут занять не мало времени.
Существует специальная команда, получающая список всех работающих процессов на определённой JVM :
$JAVA_HOME/bin/jps

Первая колонка - это и есть pid запущенных Java процессов.
C помощью следующей команды мы сможем получить stacktrace (характеристику текущего состояния) всех запущенных процессов, либо определённого процеса :

$JAVA_HOME/bin/jstack
[pid]

GWT & Spring MVC & Hibernate(JPA). Web приложения из 3х частей

Нашёл интересный пример (аля туториал) как собирать веб приложение в связке : GWT + Spring + Hibernate c JPA .
Пример достаточно прост , но довольно подробный. Разработка приложения разбита на 3 части.
Первая часть. Создаём в нашей IDE GWT проект. Создаём нужные конфиг файлы, пишем GWT код , и компилируем в две JavaScript библиотеки.
Вторая часть. Создаём Spring MVC + Hibernate проект. MVC приложение - создаём нужные конфиг файлы, контроллеры, представления. Интегрируем библиотеки из части 1 в проект.
Часть 3. Создаём классы по работе с БД. Используем Hibernate проект с JPA аннотациями.

Повторюсь, всё расписано очень подробно , код полностью предоставлен, в коде достаточно много коментариев.
Я сам этот проект в кучу не собирал, просто из за банального отсутствия времени, хотя интересно было бы попробовать.

туториал смотреть тут (язык англ.)

13 октября 2008

Интернационализация и локализация в Spring MVC

Интерфейс ApplicationContext расширяет интерфейс называемый MessageSource , который предоставляет функциональность по интернационализации приложений. (Подробней)
Существует две реализации описанного интерфейса : StaticMessageSource и
ResourceBundleMessageSource . Если быть точнее они реализуют не сам MessageSource, а его дочерний класс HierarchicalMessageSource, который кроме прочего позволяет иерархически обрабатывать сообщения.
StaticMessageSource - тяжёлый в использовании, но позволяющий програмно добавлять сообщения в список заготовленных сообщений, что далеко не всегда нужно.
ResourceBundleMessageSource рассмотрим болле подробно с помощью примера:
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>format</value>
<value>exceptions</value>
</list>
</property>
</bean>

Тут мы зарегистрировали бин, который будет искать messages в двух файлах:

format.properties
errors.properties

Это файлы используемые по умолчанию, но если в вашем броузере установлена какая то специфическая локализация ,

то сначала будут искатся файлы характерные для этой локализации ,
например для украинского языка:
format_uk.properties
errors_uk.properties

для немецкого
format_de.properties
errors_de.properties

и так далее ..

Все выше перечисленные файлы необходимо разместить в CLASSPATH.
В каждом из файлов в столбик записаны код сообщения и их значения для определённого языка.
Например
# в файле 'format.properties'
message=Hello world message!

Или пример по сложнее:
# в файле 'errors_uk.properties'
argument.required=Поле '{0}' є обов`язковим для заповнення

Для того что бы вывести эти сообщения на jsp странице используется тег spring:message .


В результате получаем вполне понятное сообщение об ошибке для украинской локализации:
Пример из файла error_uk :
Поле Address є обов`язковим для заповнення

10 октября 2008

UKраина или UnitedKingdom. Правильная локализация

Каждый современный браузер предоставляет возможность выбрать язык по умолчанию или даже несколько языков, и проставить среди них приоритеты.
В FF это можно сделать с помощью меню Инструменты - Настройка - Содержимое - Языки - Выбрать.
В Опере - Инструменты - Настройки - Языки - Настройки
В ИЕ : Свойства обозревателя - Общие - Языки

В общем то ничего необычного, удобно и практично. Но это предистория, фишка в другом. Доменные имена для страны Украина заканчиваются на .UA, на номерах присутствуют буквы UA.
Так почему же в настройках локализации, сокращение для украинской локализации UK ? Мне не понятно. Видимо в разработке этого стандарта из Украины никто не участвовал , да из Великобритании тоже.

P.S. Возможно некоторым этот пост показался глупостью, не имеющим значения. Но это не так, почему это не так, я опишу в одном из следующих сообщений где буду рассказывать как происходит локализациия приложений в современных веб фрэймворках, в частности в Spring Framework.

09 октября 2008

Spring MVC. Преобразование данных

Spring MVC: Failed to convert property value of type [java.lang.String] to required type ...

Вот такую ошибку вы получите если захотите создать html форму с текстовым полем , а пожелаете сохранить этот текст, в класс Date (например).

Сделать это можно с помощью следующего кода
Контроллер:

//...
setupFormWithDate(ModelMap model){
java.util.Date nowDate = new Date(System.currentTimeMillis());
model.addAttribute("someDate",nowDate);
return "form";
}
//...

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

<!-- ... -->
<form:input path="${someDate}" />
<!-- ... -->


Решается такая проблема довольно просто. При инициализации необходимо рассказать спрингу как реагировать на поля в которых мы вводим данные типа дата.

@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}

В SpringFramework существует специальный класс CustomDateEditor , в котором
реализована логика преобразования нашего объекта типа Date в строку и наоборот. Первый параметр в конструкторе CustomDateEditor формат представления даты как строки, в нешем случае год-месяц-день. Этот класс позаботиться что-бы nowDate из первого примера, преобразовался в
указанный формат и вывелся на форму, при отправке формі на сервер, текстовое значение поля someDate будет также обрабатывать класс CustomDateEditor и преобразует его в правильную дату.
Второй параметр определяет допускаются ли пустые значения в этом поле.

Более сложный вариант, когда мы хотим вывести в текстовое (либо другое) поле значение, которое не принадлежит к классу созданному нами.

Например у нас есть класс Address:
class Address {
int zip;
String country;
String region;
String city;
String street;
String house;
int floor;
int flat;

public String toString(){
return ""+zip+":"+country+":"+region // + ...
}
}
и есть класс User у которого есть домашний и рабочий адреса. Предположим, что
выделять 16 полей на форме под адресса мы не хотим, потому что они будут занимать слишком много места.
Не проблема, создадим 2 поля, назовём их workAddress и homeAddress.
Теперь нам нужен некий Custom Editor, который будет знать как преобразовывать из тектового значения в класс Address и наоборот.
Так как стандартного такого для нашего класса нет и не будет, то создадим свой. Этот класс должен расширять java.beans.PropertyEditorSupport и перегрузить один из его методов , а именно : setAsText. Назовём наш редактор : AddressPropertyEditor.
P.s. обратите внимание, в классе Address я уже создал стандартный метод (toString) , который преобразует объект Address в строку, где все члены разделены двоеточием. Но это же можно было сделать и в классе AddressPropertyEditor, с помощью перегрузки метода getAsText.

Наш редактор свойств будет выглядеть приблизительно так:
class AddressPropertyEditor extends PropertyEditorSupport {

@Override
public void setAsText(String text) {
Address address;
// начало логики преобразования из строки в Address
// TODO text.split(':')
// check if text is correct , throw exceptions if it's not
// TODO address set properies
// конец логики преобразования из строки в Address
setValue(address); // устнавливаем значения типа Address
}

Остался последний штрих. По аналогии с регистрацией CustomDateEditor, надо
зарегистировать редактор для преобразования нашего адресса:

@InitBinder
//...
binder.registerCustomEditor(Address.class, new AddressPropertyEditor());

P.s. Пример с адресом я выбрал конечно яркий, но не реальный.
Другой хороший пример(который я только что придумал).
В одно текстовое поле добавляется List<String> - список текстовых значений. Например список тегов к сообщению в блоге вводиться именно таким образом.

08 октября 2008

File Uploading with Spring Framework

Наверное ни один веб портал не может обойтись без такой операции как загрузка файлов на сервер.
Особенно актуальная єта задача для больших веб приложений, которые разрабатываются в основном на java ee.
В  этой заметке я рассмотрю как осуществляется аплоад файлов при использовании Spring фрэймоврка 2.5 (с использованием аннотаций).

Сначала нам необходимо зарегистрировать специальный бин - MultipartResolver, который будет сканировать все запросы к серверу и искать формы с типом multipart (т.е. с файлом для загрузки на сервер). Если такая форма найдётся этот бин передаст её для дальнейшей специальной обработки в сервлет MultipartHttpServletRequest, который и закачает наш файл.
<!-- MultipartResolver for parsing file uploads, implementation for Commons FileUpload -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
Всё это Spring сам делать не умеет, но хорошо это умеет делать Apache Commons FileUpload,
функциональность которого и вызывается через Spring Framework. Так что необходимо подключить commons-fileupload.jar и commons-io.jar библиотеки.

Настройка завершена, теперь код.
Создаём jsp страничку с multipart формой и единственным параметром file типа file. Назовём её например uploadFile.jsp:
<form action="uploadFile.html" method="post" encType="multipart/form-data">
  <tr>
      <td>Content</td>
     <td><input type="file" name="file"><br></td>
  </tr>
  <tr>
      <td colspan="2"><input type="submit" value="Upload file"></td>
  </tr>
</form>
 
Создаём класс контроллера.
Нам необходимо обрабатывать минимум 2 запроса. Первый - для отображения формы, через которую будет производиться загрузка файла, второй для обработки непосредственной загрузки файла (submit формы).
Например:
@Controller
class UploadController {

    @RequestMapping(value = "/file.html", method = RequestMethod.GET)
    public String setupUploadFile(){
        return "uploadFile";
    }
   
    @RequestMapping(value = "/uploadFile.html")   
    public String processUploadPreview(
            @RequestParam("file") MultipartFile file
            ){
      // Сохраняем файл на диск...
      // Содержание загруженного файла можно получить с помощь:
      // file.getInputStream()
      // имя и расширения файла можно извлечь из свойств
      // file.getName() , file.getContentType()
        return "redirect:index.html";
    } 
}


Это всё. Можно переходить к тестированию.

Аспектно ориентированное программирование: Основы

В своём блоге Антон Наумов подробно рассказывает о основах АОП и принципах его применения вместе со Spring Framework. link

Если этого вам оказалось мало, более развёрнутый взгляд на AOP  можно услышать в интервью с исследователями из Siemens (Christa Schwanninger & Iris Groher ) : link2
We discuss the fundamentals of AOP, define many of the relevant terms
and also look at how and where AOP is used in practice, as well as at
some current research trends.

P.s. если вы не поняли что написано выше, на ссылку2 нет смысла нажимать, интервью на англ. языке.

06 октября 2008

Java подкасты

Теперь скучать во время поездок в транспорте любителям Java не придётся. Вашему вниманию предоставляется список подкастов, которые могут быть интересны Java программисту.
The Art of programming - подкаст о программировании на русском языке, много внимание уделяется Java и сопутствующим технологиям.

Java Posse - известнейший Java подкаст на англ. языке, уже более 200 выпусков.

ZDot podcast - ещё один подкаст на англ. языке посвящённый в основном Java EE технологиям (есть несколько интересных выпусков по JSF и hibernate).

JavaOne podcast - подкаст на англ. языке посвящённый конференции JavaOne

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

05 октября 2008

Поиск обновлён

Строка поиска размещённая на этом сайте в колонке справа теперь ищет только по ресурсам имеющим непосредственное отношение к Java и сопутствующим технологиям. Список сайтов постоянно обновляется.

P.s. Если хотите что-бы и ваш сайт/блог попал в избранный список, пишите об этом в комментариях.

01 октября 2008

Разместить баннер бесплатно!

Если вы владелец информационного ресурса, каким либо образом связанного с ИТ в целом и с программированием (java) в частности, я готов разместить ссылку или красивый баннер на ваш сайт в своём блоге, причём совершенно безвозмездно, тоесть даром. Пишите.