11.27.2012

Маленькая статья по Hibernate Bidirectional Association Annotation.

Я здесь кратко описал все Bidirectional Association которые есть у Hibernate посредством Annotation.

1. Hibernate: Annotation one-to-many/many-to-one(foreign-key)

-=Relationship=-
person(one) <-> address(many)

-=DB Schema=-
create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
    )

create table EVENTS (
        id bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        personId bigint not null,
        primary key (id)
    )

alter table EVENTS 
        add constraint FK7A9AD519B59AA19 
        foreign key (personId) 
        references Persons(personId)
-=Annotation=-
public class Person {
    @Id
    @GeneratedValue()
    @Column(name = "personId")
    private Long id;
    
    @OneToMany(cascade =CascadeType.ALL,fetch = FetchType.EAGER,
            mappedBy = "person1")
    private List events = new ArrayList();
}

public class Event {
    @Id @GeneratedValue(generator="increment")
 @GenericGenerator(name="increment", strategy = "increment")
    private Long id;
    
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "personId",referencedColumnName = "personId",nullable = false)
    private Person person1;
}
-=Доступ к объекту=-
person1.getEvents().toString();
event.getPerson1().toString();
2. Hibernate: Annotation one-to-many/many-to-one(join table)

-=Relationship=-
Person(one) <-> Event(many)

-=DB Schema=-
create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
    )

create table EVENTS (
        eventId bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (eventId)
    )

create table PersonEvent (
        personId bigint,
        eventId bigint not null,
        primary key (eventId)
    )

alter table PersonEvent 
        add constraint FK489E5C25B59AA19 
        foreign key (personId) 
        references Persons(personId)

alter table PersonEvent 
        add constraint FK489E5C25418989BB 
        foreign key (eventId) 
        references EVENTS(eventId)
-=Annotation=-
@Entity
@Table(name="Persons")
public class Person {
    @Id
    @GeneratedValue()
    @Column(name = "personId")
    private Long id;
    
    @OneToMany(cascade =CascadeType.ALL,fetch = FetchType.EAGER)
    @JoinTable(name = "PersonEvent"
    ,joinColumns = @JoinColumn(name = "personId")
    ,inverseJoinColumns = @JoinColumn(name = "eventId"))    
    private List events = new ArrayList();
}

@Entity
@Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
 @GenericGenerator(name="increment", strategy = "increment")
    @Column(name = "eventId")
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinTable(name = "PersonEvent"
    ,joinColumns = @JoinColumn(name = "eventId")
    ,inverseJoinColumns = @JoinColumn(name = "personId"))
    private Person person1;
}
-=Доступ к объекту=-
person1.getEvents().toString();
event.getPerson1().toString();
3. Hibernate: Annotation one-to-one(primary-key)

-=Relationship=-
Person(one) <-> Event(one)

-=DB Schema=-
create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
    )

create table EVENTS (
        eventId bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (eventId)
    )
-=Annotation=-
@Entity
@Table(name="Persons")
public class Person {
    @Id
    @GeneratedValue()
    @Column(name = "personId")
    private Long id;
    
    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn    
    private Event events;
}

@Entity
@Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
 @GenericGenerator(name="increment", strategy = "increment")
    @Column(name = "eventId")
    private Long id;
   
    @OneToOne(cascade = CascadeType.ALL,mappedBy = "events")
    private Person person1;
}
-=Доступ к объекту=-
person1.getEvents().toString();
event.getPerson1().toString();
4. Hibernate: Annotation one-to-one(foreign-key)

-=Relationship=-
Person(one) <-> Event(one)

-=DB Schema=-
create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        eventId bigint,
        primary key (personId)
    )

create table EVENTS (
        eventId bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (eventId)
    )

alter table Persons 
        add constraint FK3AC8679E418989BB 
        foreign key (eventId) 
        references EVENTS(eventId)
-=Annotation=-
@Entity
@Table(name="Persons")
public class Person {
    @Id
    @GeneratedValue()
    @Column(name = "personId")
    private Long id;
    
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name= "eventId",referencedColumnName = "eventId")    
    private Event events;
}

@Entity
@Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
 @GenericGenerator(name="increment", strategy = "increment")
    @Column(name = "eventId")
    private Long id;
    
    @OneToOne(cascade = CascadeType.ALL,mappedBy = "events")
    private Person person1;
}
-=Доступ к объекту=-
person1.getEvents().toString();
event.getPerson1().toString();
5. Annotation one-to-one(join table)

-=Relationship=-
Person(one) <-> Event(one)

-=DB Schema=-
create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
    )

create table EVENTS (
        eventId bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (eventId)
    )

create table PersonEvent (
        eventId bigint,
        personId bigint not null,
        primary key (personId)
    )

alter table PersonEvent 
        add constraint FK489E5C25B59AA19 
        foreign key (personId) 
        references Persons(personId)

alter table PersonEvent 
        add constraint FK489E5C25418989BB 
        foreign key (eventId) 
        references EVENTS(eventId)
-=Annotation=-
@Entity
@Table(name="Persons")
public class Person {
    @Id
    @GeneratedValue()
    @Column(name = "personId")
    private Long id;
    
    @OneToOne(cascade = CascadeType.ALL)
    @JoinTable(name = "PersonEvent"
    ,joinColumns = @JoinColumn(name = "personId",referencedColumnName = "personId")
    ,inverseJoinColumns = @JoinColumn(name = "eventId",referencedColumnName = "eventId"))    
    private Event events;
}

@Entity
@Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
 @GenericGenerator(name="increment", strategy = "increment")
    @Column(name = "eventId")
    private Long id;
    
    @OneToOne(cascade = CascadeType.ALL,mappedBy = "events")
    private Person person1;
}
-=Доступ к объекту=-
person1.getEvents().toString();
event.getPerson1().toString();
6. Hibernate: Annotation many-to-many (join table)

-=Relationship=-
Person(many) <-> Event(many)

-=DB Schema=-
create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
    )

create table EVENTS (
        eventId bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (eventId)
    )

create table PersonEvent (
        personId bigint not null,
        eventId bigint not null
    )

alter table PersonEvent 
        add constraint FK489E5C25B59AA19 
        foreign key (personId) 
        references Persons(personId)

alter table PersonEvent 
        add constraint FK489E5C25418989BB 
        foreign key (eventId) 
        references EVENTS(eventId)
-=Annotation=-
@Entity
@Table(name="Persons")
public class Person {
    @Id
    @GeneratedValue()
    @Column(name = "personId")
    private Long id;
    
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "PersonEvent"
    ,joinColumns = @JoinColumn(name = "personId")
    ,inverseJoinColumns = @JoinColumn(name = "eventId"))    
    private List events = new ArrayList();
}

@Entity
@Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
 @GenericGenerator(name="increment", strategy = "increment")
    @Column(name = "eventId")
    private Long id;
    
    @ManyToMany(cascade = CascadeType.ALL,mappedBy = "events")
    private List person1;
}
-=Доступ к объекту=-
person1.getEvents().toString();
event.getPerson1().toString();

11.26.2012

Маленькая статья по Hibernate Unidirectional Association Annotation.

Я здесь хочу кратко описать все Unidirectional Association которые есть у Hibernate посредством Annotation.

1. Hibernate: Annotation one-to-many (foreign-key)

-=Relationship=-
Person(one) -> Event(many)

-=DB Schema=-
 
create table Persons (
        id bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (id)
    )

create table EVENTS (
        id bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        events_ID bigint,
        primary key (id)
    )

alter table EVENTS  add constraint FK7A9AD519F2DCD0EA 
        foreign key (events_ID) references Persons(id)

-=Annotation=-
@Entity
@Table(name = "EVENTS")
public class Event { 
    @Id
    @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;
}

@Entity
@Table(name="Persons")
public class Person {
    @Id
    @GeneratedValue()
    private Long id;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "events_ID")
    private Set events = new HashSet();
}
-=Доступ к объекту=-
person1.getEvents().toString();
2. Annotation one-to-many(join table)

-=Relationship=-
Person(one) -> Event(many)

-=DB Schema=-
create table EVENTS (
        id bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (id)
    )

create table PersonEvent (
        personId bigint not null,
        eventId bigint not null,
        primary key (personId, eventId),
        unique (eventId)
    )

create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
    )

alter table PersonEvent 
        add constraint FK489E5C25B59AA19 
        foreign key (personId) 
        references Persons(personId)

alter table PersonEvent 
        add constraint FK489E5C25418989BB 
        foreign key (eventId) 
        references EVENTS(id)

-=Annotation=-
@Entity @Table(name = "Persons")
public class Person {
    @Id @GeneratedValue() @Column(name = "personId")
    private Long id;    

    @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    @JoinTable(name = "PersonEvent"
    ,joinColumns = @JoinColumn(name = "personId")
    ,inverseJoinColumns = @JoinColumn(name = "eventId"))
    private Set events;
}

@Entity @Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;
}
-=Доступ к объекту=-
person1.getEvents().toString();
3. Annotation one-to-one(foreign-key)

-=Relationship=-
Person(one) -> Event(one)

-=DB Schema=-
create table EVENTS (
        id bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (id)
    )

create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        id bigint,
        primary key (personId)
    )

alter table Persons 
        add constraint FK3AC8679E939555A1 
        foreign key (id) 
        references EVENTS(id)
-=Annotation=-
@Entity @Table(name = "Persons")
public class Person {
    @Id @GeneratedValue() @Column(name = "personId")
    private Long id;   

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "id")
    private Event events;
 }

@Entity @Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;
}
-=Доступ к объекту=-
person1.getEvents().toString();
4. Annotation one-to-one(primary-key)

-=Relationship=-
Person(one) -> Event(one)

-=DB Schema=-
create table EVENTS (
        id bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (id)
    )

create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
    )
-=Annotation=-
@Entity @Table(name = "Persons")
public class Person {
    @Id @GeneratedValue() @Column(name = "personId")
    private Long id;  

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn(name = "personId",referencedColumnName = "eventId")
    private Event events;
}

@Entity @Table(name = "EVENTS")
@ToString  @EqualsAndHashCode
public class Event {
    @Id @GeneratedValue(generator="increment")
 @GenericGenerator(name="increment", strategy = "increment")
    private Long id;
}
-=Доступ к объекту=-
person1.getEvents().toString();
5. Annotation one-to-one(join table)

-=Relationship=-
Person(one) -> Event(one)

-=DB Schema=-
create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
    )

create table EVENTS (
        id bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (id)
    )

create table PersonEvent (
        eventId bigint,
        personId bigint not null,
        primary key (personId)
    )

alter table PersonEvent 
        add constraint FK489E5C25B59AA19 
        foreign key (personId) 
        references Persons(personId)

alter table PersonEvent 
        add constraint FK489E5C25418989BB 
        foreign key (eventId) 
        references EVENTS(id)
-=Annotation=-
@Entity @Table(name = "Persons")
public class Person {
    @Id @GeneratedValue() @Column(name = "personId")
    private Long id;   

    @OneToOne(cascade = CascadeType.ALL)
    @JoinTable(name="PersonEvent"
            ,joinColumns = @JoinColumn(name = "personId")
            ,inverseJoinColumns = @JoinColumn(name = "eventId"))
    private Event events;
}

@Entity @Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;
}
-=Доступ к объекту=-
person1.getEvents().toString();
6. Hibernate: Annotation many-to-one(foreign-key)

-=Relationship=-
Person(many) -> Event(one)

-=DB Schema=-
create table EVENTS (
        id bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (id)
    )

create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        eventId bigint,
        primary key (personId)
    )

alter table Persons 
        add constraint FK3AC8679E418989BB 
        foreign key (eventId) 
        references EVENTS(id)
-=Annotation=-
@Entity @Table(name = "Persons")
public class Person {
    @Id @GeneratedValue() @Column(name = "personId")
    private Long id;   

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "eventId"
            ,referencedColumnName = "id")
    private Event events;
}

@Entity @Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;
}
-=Доступ к объекту=-
person1.getEvents().toString();
7. Hibernate: Annotation many-to-one (join table)

-=Relationship=-
Person(many) -> Event(one)

-=DB Schema=-
create table Persons (
        personId bigint generated by default as identity,
        fName varchar(255),
        sName varchar(255),
        primary key (personId)
)

create table EVENTS (
        id bigint not null,
        EVENT_DATE timestamp,
        title varchar(255),
        primary key (id)
    )

create table PersonEvent (
        enentId bigint,
        personId bigint not null,
        primary key (personId)
    )

alter table PersonEvent 
        add constraint FK489E5C25B59AA19 
        foreign key (personId) 
        references Persons(personId)

alter table PersonEvent 
        add constraint FK489E5C2533E2C4C3 
        foreign key (enentId) 
        references EVENTS(id)
-=Annotation=-
@Entity @Table(name = "Persons")
public class Person {
    @Id @GeneratedValue() @Column(name = "personId")
    private Long id;    

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinTable(name = "PersonEvent"
    ,joinColumns = @JoinColumn(name = "personId",referencedColumnName = "personId")
    ,inverseJoinColumns = @JoinColumn(name = "enentId",referencedColumnName = "id"))
    private Event events;
}

@Entity @Table(name = "EVENTS")
public class Event {
    @Id @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;
}
-=Доступ к объекту=-
person1.getEvents().toString();

11.12.2012

Spring mvс и Internationalization (I18N).

Для работы I18N в нашем Spring mvс приложении нужно правильно сконфигурировать компоненты которые отвечают за работу с локалью и интернациональными сообщениями, так называемыми файлами BundleMessage.properties. Для этого нам нужно настроить интерфейс org.springframework.context.MessageSource который позволяет нам работать с I18N файлами в зависимости от установленой локали. Определить текущую локаль запроса нам помогает интерфейс org.springframework.web.servlet.LocaleResolver, а изменять org.springframework.web.servlet.i18n.LocaleChangeInterceptor. Все что нужно запомнить 1-й интерфейс отвечает за место где хранятся файлы ресурсов, 2-й где хранится локаль пользователя, 3-й отвечает за смену локали. Давайте расмотрим все по порядку.
Нам нужны 2 файла Application.properties c данными:
Button.text=Click me english
и Application_ru_RU.properties:
Button.text=Click me По русски!
в зависимости от локали мы будем использовать тот или иной файл для вывода сообщений. За пути где лежат файлы ответственнен класс ReloadableResourceBundleMessageSource который наследуется от интерфейса MessageSource:
<beans:bean  class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
            id="messageSource"
            p:basenames="WEB-INF/i18n/Application"
            p:fallbackToSystemLocale="false"
            p:fileEncodings="UTF8"
            p:defaultEncoding="UTF8"
            /> 
обратите внимание на параметры p:basenames="WEB-INF/i18n/Application" - указывает путь где нужно искать наши porperties файлы, p:fileEncodings="UTF8" p:defaultEncoding="UTF8" указываем  что исходная кодировка наших porperties файлов UTF8. И так перейдем к следующему интерфейсу - LocaleResolver который ответственен за установку Locale отображаемой страницы, есть несколько класов которые реализуют этот интерфейс и соответсвенно их можно использовать в настройке Spring контекста web приложения, давайте расмотрим их - как они реализуют смену и установку Locale. Первый из них AcceptHeaderLocaleResolver - он берет свою Locale из заголовка HTTP Header Accept-Language, как мы знаем обычно этот заголовок устанавливается браузером клиента и изменить его программно нельзя, используется поумолчанию:
<beans:bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"
                id="localeResolver" />
Второй это CookieLocaleResolver использует для хранения Locale технологию Cookie, соответственно можно задать имя переменной Cookie, в нашем случае в p:cookieName="localeUser" будет храниться наша Locale и каждый пользователь может переустановить его на свое усмотрение.
<beans:bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
                id="localeResolver" p:cookieName="localeUser" p:defaultLocale="en_US"/>
Если в Cookie нет установленного localeUser параметра то берется по умолчанию default значение p:defaultLocale="en_US" иначе используется Locale из заголовка HTTP Header Accept-Language. Следующий FixedLocaleResolver устанавливает фиксированную Locale на все время жизни web приложения параметр p:defaultLocale="en_US", в дальнейшем параметр не может изменяться программно.
<beans:bean class="org.springframework.web.servlet.i18n.FixedLocaleResolver"
                id="localeResolver" p:defaultLocale="en_US"/>
И последний SessionLocaleResolver хранит Locale в сессии программы (HttpSession)если нет сохраненного значения в сессии то берется по умолчанию default значение p:defaultLocale="en_US" а если не установлено p:defaultLocale то используется Locale из заголовка HTTP Header Accept-Language. Программно может меняться.
<beans:bean class="org.springframework.web.servlet.i18n.SessionLocaleResolver"
                id="localeResolver" p:defaultLocale="en_US"/>
И напоследок хочу упомянуть интерфейс который позволяет нам менять мокаль программно LocaleChangeInterceptor:
<interceptors>
        <beans:bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
                    p:paramName="lang"/>
    </interceptors>
что бы сменить локаль нам нужно только отослать переменную lang c нужной локалью например ru_RU на http://localhost:8080/phone/spring/?lang=ru_RU название переменной настраивается параметром p:paramName="lang".
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
 
 xsi:schemaLocation="
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
 <!-- Enables the Spring MVC @Controller programming model -->
 <annotation-driven />

 <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
 <resources mapping="/resources/**" location="/resources/" />

 <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
 <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <beans:property name="prefix" value="/WEB-INF/views/" />
  <beans:property name="suffix" value=".jsp" />
        <beans:property name="contentType" value="text/html;charset=UTF-8"/>
 </beans:bean>
 
 <!-- Imports user-defined @Controller beans that process client requests -->
 <beans:import resource="controllers.xml" />

    <beans:bean  class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
            id="messageSource"
            p:basenames="WEB-INF/i18n/Application"
            p:fallbackToSystemLocale="false"
            p:fileEncodings="UTF8"
            p:defaultEncoding="UTF8"
            />
    <!-- 1 -->
    <!--<beans:bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"
                id="localeResolver" />-->
    <!-- 2 -->
    <!--<beans:bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
                id="localeResolver" p:cookieName="localeUser" p:defaultLocale="en_US"/>
    -->
    <!-- 3 -->
    <!--<beans:bean class="org.springframework.web.servlet.i18n.FixedLocaleResolver"
                id="localeResolver" p:defaultLocale="en_US"/>-->
    <!-- 4 -->
    <beans:bean class="org.springframework.web.servlet.i18n.SessionLocaleResolver"
                id="localeResolver" p:defaultLocale="en_US"/>
    <interceptors>
        <beans:bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
                    p:paramName="lang"/>
    </interceptors>
 
</beans:beans>
Если вы используете для отображения страницы jsp то вы должны использовать Spring Tag Library для работы с internationalization (I18N), для этого вам необходимо в начало страницы добавить <%@ taglib uri="http://www.springframework.org/tags" prefix="msg" %> в нашем случае мы создаем переменную и присваиваем ей значение Button.text выводим значение переменной ${text}
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="msg" %>
<%@ page session="false" %>
<html>
<head>
 <title>Home</title>
</head>
<body>
<h1> 
 Hello world!
</h1>
  <msg:message code="Button.text" var="test"/>
  ${test} <br/> ${pageContext.response.locale} <br/> ${controllerMessage}
</body>
</html>
и на последок обязательно нужно следить за локализацией всего web приложения от начала и до конца все файлы, все ресурсы, все запросы, в моем приложении по умолчанию используют кодировку UTF-8:
Первое все символы в запросе и ответе UTF-8
<!-- Creates the Spring Container shared by all Servlets and Filters -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
Второе все файлы набраны в кодировке UTF-8. Третье в jsp файле установлены заголовки
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page pageEncoding="UTF-8" %>
...
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<head> 
в четвертых на правильную кодировку настроен contentType класса InternalResourceViewResolver
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/"/>
        <beans:property name="suffix" value=".jsp"/>
        <beans:property name="contentType" value="text/html;charset=UTF-8"/> 
</beans:bean>
в пятых правильно настроен p:fileEncodings и p:defaultEncoding класса ReloadableResourceBundleMessageSource
<beans:bean  class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
            id="messageSource"
            p:basenames="WEB-INF/i18n/Application"
            p:fallbackToSystemLocale="false"
            p:fileEncodings="UTF8"
            p:defaultEncoding="UTF8"
            />
в шестых использую maven для компиляции приложения, у него настроена кодировка при сборке на UTF-8
          <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                    <encoding>UTF-8</encoding>
                </configuration>
          </plugin>
и в седьмых если использую tomcat то настраиваю Connector параметром URIEncoding="UTF-8"
<Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" URIEncoding="UTF-8"/>
если использую подключение к БД настраиваю передачу и хранение данных в нужной кодировке. И так локализация приложения это комплексное действие при котором нужно настраивать всЁ приложение на работу с определенной кодировкой, в моем случае используется - UTF-8.
 source code

10.26.2012

Apache Tika.

Apache Tika - библиотека предназначенная для определения, извлечения данных и метаданных из различных типов файлов в простой текстовый формат plan text, для последующего анализа содержимого файла и принятия решения что же с ним(файлом) далее делать. Очень часто tika используется как парсер текста файла, и извлеченные данные передаются для дальнейшего анализа поисковым движкам которые в свою очередь индексируют файл и его содержимое. Типы файлов которые поддерживает tika можно посмотреть на сайте http://tika.apache.org/1.2/formats.html. И так  давайте перейдем к работе с парсером tika, что для этого нужно: прежде всего файл, пусть для нашего примера мы будем парсить PDF - файл, далле нам нужен сам  парсер будем использовать спецефический заточенный под PDF-файл PDFParser, но если мы не знаем точный тип файла можно использовать и AutoDetectParser который сам принимает решение, какой парсер вызывать. У парсера есть метод public void parse(java.io.InputStream stream, org.xml.sax.ContentHandler handler,  org.apache.tika.metadata.Metadata metadata, org.apache.tika.parser.ParseContext context); который парсит файл, первый параметр принимает InputStream, источник что мы разбираем в нашем случае это InputStream is2 = new FileInputStream(file); второй параметр ContentHandler будет содержать тело документа/текст, третий параметр будет содержать метаданные - кто создал, когда и т.д., четвертый параметр какой xml-парсер будет использоваться. Давайте рассмотрим пример подробно:
package com.vit;

import org.apache.log4j.Logger;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class TikaSample {
    private static final String filename = "bs12.pdf";

    public TikaSample() throws IOException, SAXException, TikaException {
        Logger log = Logger.getLogger(this.getClass().getName()); //create Logger
        Metadata metadata = new Metadata(); //create metadata
        Tika tika = new Tika(); //create tika
        InputStream is = getClass().getResourceAsStream(filename);
        File file = new File(filename);
        InputStream is2 = new FileInputStream(file);// create source InputStream
        ParseContext pc = new ParseContext(); //create xml-парсер
        ContentHandler ch = new BodyContentHandler(-1);//сдесь будет содержаться тело документа в виде plan text
        String mimeType = tika.detect(is);//определяем mimeType нашего документа
        metadata.set(Metadata.CONTENT_TYPE, mimeType);//устанавливаем mimeType
        PDFParser parser = new PDFParser(); //create PDFParser
        //AutoDetectParser parser = new AutoDetectParser();//create универсальный парсер который на основе mimeType  принимает решение какой использовать узкоспециализированный парсер
        parser.parse(is2, ch, metadata, pc); //разбор файла на мелкие кусочки
        log.info(ch.toString());//выводим текст документа
        for (String name : metadata.names()) {//выводим метаданные документа
            log.info(name + ": " + metadata.get(name));
        }
        if (is2 != null) is2.close();
        if (is != null) is.close();
    }

    public static void main(String[] args) throws IOException, SAXException, TikaException {
        TikaSample tikaSample = new TikaSample();
    }
}
обратите внимание на -1 при создании  new BodyContentHandler(-1); иначе будет ошибка если большой файл по размеру, это связано с нехваткой памяти куда будет загружается наш документ: Exception in thread "main" org.apache.tika.sax.WriteOutContentHandler$WriteLimitReachedException: Your document contained more than 100000 characters, запускаем нашу программу и получаем такой результат:
...
текст документа 
...
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <meta:creation-date: 2005-04-22T18:10:03Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <dcterms:modified: 2005-04-23T05:28:17Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <meta:save-date: 2005-04-23T05:28:17Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <dcterms:created: 2005-04-22T18:10:03Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <Last-Modified: 2005-04-23T05:28:17Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <date: 2005-04-22T18:10:03Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <modified: 2005-04-23T05:28:17Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <xmpTPg:NPages: 25>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <Creation-Date: 2005-04-22T18:10:03Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <title: PC World Russia CD, May 2005>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <created: Fri Apr 22 22:10:03 MSD 2005>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <producer: Модуль Acrobat Web Capture 6.0>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <Content-Type: application/pdf>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <Last-Save-Date: 2005-04-23T05:28:17Z>
и конечно же приведу файл pom.xml с зависимостями:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.vit</groupId>
    <artifactId>spring-jpa-utility</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>Spring JPA</name>

    <properties>
        <tika>1.2</tika>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-core</artifactId>
            <version>${tika}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-parsers</artifactId>
            <version>${tika}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox-app</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>1.7.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-app</artifactId>
            <version>${tika}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Внутренняя кухня hibernate.

Всем новичкам кажется что ORM Hibernate делает разработку проще и код эфективней, но если не знать, некоторых особенностей, то программирование с использованием ORM Hibernate преврашается в кромешный ад. И так что же нужно знать новичку о Hibernate - первое это способ применения, есть стандартный патерн Session per View, который предполагает последовательность правильных действий: Открыть сессию, начать транзакцию, выполнить действия над "pojo-объектом", построить представление на основе "pojo-объекта", закрыть транзакцию, закрыть сессию:
// create a event...
  Session session = sessionFactory.openSession();
  session.beginTransaction();
                Event event = new Event( "Our very first event!", new Date() );
  session.save( event );
  session.getTransaction().commit();
                System.out.println( "Event create" );
  session.close(); 
после закрытия сессии все данные не должны использоваться больше и участвовать в работе приложения. При этом использовать "pojo-объекты" можно только в одном потоке,  который открыл сессию, иначе в работе Hibernate возможны ошибки. Почему нельзя использовать "pojo-объект" после закрытия сессии это связано с особенностью работы Hibernate со сложными "pojo-объектами" которые имеют связи один-к-одному(One-to-one), один-ко-многим(One-to-many) и т.д. при создании связи по умолчанию Hibernate применяет стратегию ленивой загрузки, т.е. за место реальной связи создается прокси-объект без его реального заполнения данными и после завершения сессии, при запросе к прокси-объекту возникает рантаймовое исключение LazyInitializationException. Если вы все-таки хотите работать с "pojo-объектом" после закрытия сессии нужно отключить стратегию ленивой загрузки и переопределить методы equals() и hashCode(). Поясню все на примере, пусть у нас связь person(one) -> address(one):

@Entity
@Table(name="PERSON")
public class Person implements Serializable {
   
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name="personId")
  private int id;

  @OneToOne
  @PrimaryKeyJoinColumn
  private Address address;

  public Address getAddress() {
    return address;
  }
}

@Entity
@Table(name = "ADDRESS")
public class Address {
  @Id
  @Column(name = "personId")
  private int id;
}
....
session.close();
person.getAddress(); --> здесь возникает исключение LazyInitializationException.
я знаю 5 или 6 методов как отключить стратегию ленивой загрузки вот один из них, нужно просто добавить аннотацию для нашего примера @Proxy(lazy=false) и все:
@Entity
@Table(name="PERSON")
@Proxy(lazy=false)
public class Person { 
....
session.close();
person.getAddress();
здесь уже не возникает исключение LazyInitializationException, так как тут уже подгружен реальный объект/коллекция объектов, но нужно быть осторожными с подгружаемыми зависимостями так как это может навредить быстродействию программы и ухудшить её работу, просто нужно найти золотую середину, посредством тестирования кода. Небольшое отступление от темы,  Hibernate нужны интерфейсы для всех сущностей если вы хотите чтобы проксировались подгружаемые объекты через Java Proxy, иначе работа идет через CGLIB, ему не нужны  интерфейсы сущностей и при помощи ASM'а  Hibernate на лету генерирует байт код прокси-объектов, выбор метода проксирования остается за вами,  по умолчанию Hibernate использует CGLIB и интерфейсы ему не нужны. Конечно мы не ищем легких путей и хотим пользоваться "pojo-объектом" и после закрытия сессии изменять их и сохранять сделанные нами изменения с помощью Hibernate, для этого как я упоминал раньше нужно переопределить методы equals() и hashCode(). Вообще я практически всегда эти важные методы наследую и периопределяю, плюс к этому всегда стараюсь наследовать итерфейс Serializable, но пропускаю конструктор "pojo-объекта" по умолчанию, т.к. при создании любого объекта как  new Person() - java автоматически за нас создает и вызывает конструктор по умолчанию. Почему я так настаиваю на переопределении методов equals() и hashCode() я постараюсь объяснить на примере, пусть у нас есть "pojo-объект" без переопределенных методов equals() и hashCode():
public class Entity {
    private int id = 0;
    ....
}
наша программа создает объект Entity и добавляет его в HashSet, далее идут проверки содержит ли HashSet точную копию объекта Entity.
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] argv) {
        Entity slimy = new Entity();
        //1
        Set failSet = new HashSet();
        System.out.println(failSet.contains(slimy)); // false
        //2
        failSet.add(slimy);
        System.out.println(failSet.contains(slimy)); // true

        // 3 ID was assigned by an ORM Hibernate 
        slimy.setId(100);
        System.out.println(failSet.contains(slimy)); // true
    }
}
  1. создаем объект и проверяем существует ли объект slimy в HashSet, его там нет // false
  2. заносим объект slimy в HashSet и проверяем существует  ли объект slimy в HashSet - он там присутствует(содержит точную копию) // true
  3. уподобляемся ORM Hibernate и меняем slimy, производим проверку и опять точная  копия содержится в HashSet // true, - ошибка!!!
переопределим методы equals() и hashCode() класса Entity:
public class Entity {
    private int id = 0;
    ....
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Entity other = (Entity) obj;
        if (id != other.id)
            return false;
        return true;
    }
}
заново выполняем программу и на 3-м шаге получаем отрицательный ответ // false объект slimy в HashSet не совпадает с измененным объектом slimy что есть правильно!  Плюс я всегда стараюсь переопределить метод toString() для правильной визуализации  тестовых данных!
Еще новичкам обязательно нужно понять и знать как работает Hibernate cache, без его понимания не стоит и пытаться использовать Hibernate, особенности работы подробно описаны на Хабрахабр'е вот 2 сылки Hibernate cache и Hibernate Cache Практика. Ну вот и все! здесь я дал 30% теории которую вы должны усвоить прежде чем начать работу с ORM Hibernate, 70% придет с практикой!

10.15.2012

Spring MyBatis H2.

В этой статье будет представлен пример интеграции Spring MyBatis + CRUD основных команд MyBatis'a. И так начнем с описания схемы базы данных H2 которая просто встраивается в Spring - schema.sql:
DROP TABLE IF EXISTS PERSON;

CREATE TABLE PERSON (
       ID INT NOT NULL AUTO_INCREMENT
     , FIRST_NAME VARCHAR(20) NOT NULL
     , LAST_NAME VARCHAR(20) NOT NULL
     , BIRTH_DATE DATE
     , UNIQUE UI_PERSON (FIRST_NAME, LAST_NAME)
     , PRIMARY KEY (ID)
);
мы создаем таблицу PERSON где у нас будут храниться данные по человеку его имя, фамилия и дата рождения. Напишем скрип наполняюший эту таблицу произвольными данными - test-data.sql:
insert into person (first_name, last_name, birth_date) values ('Lopanov', 'Vitaly', '1981-08-23');
insert into person (first_name, last_name, birth_date) values ('Kozirev', 'Valera', '1952-01-01');
insert into person (first_name, last_name, birth_date) values ('Aristov', 'Sergey', '1964-10-13');
отобразим нашу табличку доменной моделью реализованной классом Person.java:
package com.vit.domain;

import java.io.Serializable;
import java.util.Date;

public class Person implements Serializable {

    private Long id;
    private String firstName;
    private String lastName;
    private Date birthDate;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", birthDate=" + birthDate +
                '}';
    }
}
опишим интерфейс доступа к данным, все операции CRUD:
package com.vit.persistence;

import com.vit.domain.Person;

import java.util.List;

public interface PersonMapper {

    public List findAll();

    public Person findById(Long id);

    public void insert(Person person);

    public void update(Person person);

    public void delete(Long id);

}
с проектируем все SQL-запросы в специальном файле PersonMapper.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.vit.persistence.PersonMapper">

    <resultMap id="personResultMap" type="Person">
        <id property="id" column="ID" />
        <result property="firstName" column="FIRST_NAME" />
        <result property="lastName" column="LAST_NAME" />
        <result property="birthDate" column="BIRTH_DATE" />
    </resultMap>

    <select id="findAll" resultMap="personResultMap">
        SELECT ID, FIRST_NAME, LAST_NAME, BIRTH_DATE
        FROM PERSON
    </select>
    
    <select id="findById" parameterType="long" resultMap="personResultMap">
        SELECT ID,FIRST_NAME,LAST_NAME,BIRTH_DATE
        FROM PERSON
        WHERE ID = #{id}
    </select>
    
    <insert id="insert" parameterType="Person" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO PERSON (FIRST_NAME, LAST_NAME, BIRTH_DATE)
        VALUES (#{firstName}, #{lastName}, #{birthDate})    
    </insert>   
    
    <update id="update" parameterType="Person">
        UPDATE PERSON SET
            FIRST_NAME = #{firstName},
            LAST_NAME = #{lastName},
            BIRTH_DATE = #{birthDate}
        WHERE ID = #{id}   
    </update>       
    
    <delete id="delete" parameterType="long">
        DELETE FROM PERSON WHERE ID = #{id}
    </delete>         
    
</mapper>
Опишем сервисный слой доступа к операциям CRUD c помощью интерфейса PersonService:
package com.vit.service;

import com.vit.domain.Person;

import java.util.List;

public interface PersonService {

    // Find all persons
    public List findAll();

    // Find by ID - person
    public Person findById(Long id);

    // Create a new or save an existing person
    public Person save(Person person);

    // Delete a person
    public void delete(Person person);

}
и реализуем интерфес доступа PersonServiceImpl:
package com.vit.service;

import com.vit.domain.Person;
import com.vit.persistence.PersonMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service("personService")
@Repository
@Transactional
public class PersonServiceImpl implements PersonService {
    @Autowired
    private PersonMapper personMapper;

    public List findAll() {
        List persons = personMapper.findAll();
        return persons;
    }

    public Person findById(Long id) {
        Person person = personMapper.findById(id);
        return person;
    }

    public Person save(Person person) {
        if (person.getId() == null) {
            insert(person);
        } else {
            update(person);
        }
        return person;
    }

    private Person insert(Person person) {
        personMapper.insert(person);
        return person;
    }

    private Person update(Person person) {
        personMapper.update(person);
        return person;
    }

    public void delete(Person person) {
        Long personId = person.getId();
        personMapper.delete(personId);
    }
}
осталось самое интересное интегрировать в Spring - MyBatis все это дело описывается парой строчек в конфигурационном файле 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"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
  http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
    <!-- 1 -->
    <jdbc:embedded-database id="dataSource" type="H2">
        <jdbc:script location="classpath:schema.sql" />
        <jdbc:script location="classpath:test-data.sql" />
    </jdbc:embedded-database>
    <!-- 2 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:annotation-driven />
    <!-- 3 -->
    <context:component-scan base-package="com.vit.service" />

    <!-- 4 Define the SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliasesPackage" value="com.vit.domain" />
    </bean>

    <!-- 5 Scan for mappers and let them be autowired -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.vit.persistence" />
    </bean>

</beans>
  1. спринг выполняет скрипты, создает и заполняет данными таблицу Person, и настраивается dataSource H2.
  2. создается менеджер транзакций - transactionManager.
  3. задается путь где Spring ищет наши компоненты.
  4. создается SqlSessionFactory mybatis'a.
  5. объект связывающий PersonMapper.xml с интерфейсом доступа к данным PersonMapper.
и осталось показать как работать со спрингом:
package com.vit;

import com.vit.domain.Person;
import com.vit.service.PersonService;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.util.*;

public class MyBatisSample {

 public static void main(String[] args) {
  GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
  ctx.load("classpath:ApplicationContext.xml");
  ctx.refresh();
  
  PersonService personService = ctx.getBean("personService", PersonService.class);

  List persons;
  
  // Find all persons
  persons = personService.findAll();
  listPersons(persons);

  // Find person by id
  persons = new ArrayList();
  System.out.println("Finding person with id 1");
  Person person = personService.findById(1L);
  persons.add(person);
  listPersons(persons);
  
  // Add new person
  System.out.println("Add new person");
  person = new Person();
  person.setFirstName("Layla");
  person.setLastName("Roberts");
  person.setBirthDate(new Date());
  personService.save(person);
  persons = personService.findAll();
  listPersons(persons);
  
  // Update person
  System.out.println("Update person with id 1");
  person = personService.findById(1L);
  person.setFirstName("Vlad");
  personService.save(person);
  persons = personService.findAll();
  listPersons(persons);

  // Delete person
  System.out.println("Delete person with id 1");
  person = personService.findById(1L);
  personService.delete(person);
  persons = personService.findAll();
  listPersons(persons);
 }
 
 private static void listPersons(List persons) {
  System.out.println("Listing persons without details:");
  for (Person person: persons) {
   System.out.println(person+"\n");
  }
 }
}
и конечно же на последок файл pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.vit</groupId>
    <artifactId>spring-mybatis</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>Spring Utility</name>

    <properties>
                <spring.framework.version>3.1.1.RELEASE</spring.framework.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.framework.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>

        <!-- H2 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.160</version>
        </dependency>

        <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.1.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

10.12.2012

Vaadin и Spring Security.

В предыдущей статье было показано как интегрировать Spring в Vaadin, продолжаем его улучшать добавив к нему поддержку Spring Security. Я не буду останавливаться на настройке Spring Security просто раскажу как происходит аутентификация - процедура проверки подлинности данных, т. е. проверка соответствия введённого пользователем пароля к учётной записи и паролю в файле application-security.xml. Приведу сразу листинг файла application-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/*" access="hasAnyRole('ROLE_USER','ROLE_ANONYMOUS')"/>
        <form-login login-page="/login" default-target-url="/" authentication-failure-url="/login_error"/>
        <logout invalidate-session="true"/>
    </http>
    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <user authorities="ROLE_USER" name="test" password="test"/>
            </user-service>
        </authentication-provider>
    </authentication-manager>
    <global-method-security pre-post-annotations="enabled"/>
</beans:beans>
из него видно что аутентификация происходит на основе формы при помощи странички /login которая дает нам ввести пользователя и пароль, если аутентификация прошла успешно то мы переходим к основной страничке приложения / если нет то выводим страничку с ошибкой /login_error. приведу сразу листинг web.xml с настройками страниц /login - login.jsp, /login_error - login_error.jsp:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
    <display-name>Vaadin Web Application</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
            /WEB-INF/application-security.xml
        </param-value>
    </context-param>

    <servlet>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <servlet-class>com.vit.AutowiringApplicationServlet</servlet-class>
        <init-param>
            <param-name>application</param-name>
            <param-value>com.vit.MyVaadinApplication</param-value>
        </init-param>
    </servlet>
    <servlet>
     <servlet-name>login</servlet-name>
     <jsp-file>/WEB-INF/jsp/login.jsp</jsp-file>
    </servlet>
    <servlet>
     <servlet-name>login_error</servlet-name>
     <jsp-file>/WEB-INF/jsp/login_error.jsp</jsp-file>
    </servlet>
    <servlet-mapping>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
     <servlet-name>login</servlet-name>
     <url-pattern>/login</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
     <servlet-name>login_error</servlet-name>
     <url-pattern>/login_error</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>
            org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>
            org.springframework.security.web.session.HttpSessionEventPublisher
        </listener-class>
    </listener>

</web-app>
страничка где вводим пользователя и пароль - листинг login.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
 <div align="center">
 Login here
 <form action= "<%= request.getContextPath() %>/j_spring_security_check" method="post">
 <table>
  <tr>
   <td>
    User
   </td>
   <td>
    <input name="j_username" value="test">
   </td>
  </tr>
  <tr>
   <td>
    Password
   </td>
   <td>
    <input type="password" name="j_password" value="test"/>
   </td>
  </tr>
  <tr>
   <td>
    <input type="submit" value="login">
   <td>
  </tr>
 </table>
 </form> 
 </div>
</body>
</html>
страничка куда попадаем если не правильно ввели данные аутентификации листинг login_error.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
 <H1 align="center">Access Denied</H1>
 <div align="left" >
        <a href="<%= request.getContextPath() %>/login" > Login </a></div>
    <div align="left" ><a href="<%= request.getContextPath() %>" > Home </a></div>
</body>
</html>
При работе с нашим приложение любому пользователю, Spring'ом присваивается роль ROLE_ANONYMOUS, если пользователь успешно прошёл аутентификацию, то ему присваивается роль ROLE_USER.
package com.vit;

public interface Roles {
    String ROLE_USER = "ROLE_USER";
    String ROLE_ANONYMOUS = "ROLE_ANONYMOUS";
}
С помощью метода hasAnyRole(ROLE_USER) мы можем узнать залогинелся ли пользователь и соответственно раздавть ему полагаемые ресурсы, данные. Сылки "Login" и "Logout" я вынеc в одельную панель HeadPanel:
package com.vit;

import com.vaadin.terminal.ExternalResource;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.BaseTheme;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.Collection;
import static com.vit.Roles.ROLE_USER;
import static com.vit.Roles.ROLE_ANONYMOUS;

public class HeadPanel extends Panel {
    public HorizontalLayout hLayout;
    public HorizontalLayout cssLayout;

    public HeadPanel() {
        setImmediate(true);
        cssLayout = new HorizontalLayout();
        cssLayout.setSpacing(true);

        hLayout = new HorizontalLayout();
        hLayout.setWidth("100%");

        if (hasAnyRole(ROLE_ANONYMOUS)) {
            Button b = new Button("LOGIN");
            b.setStyleName(BaseTheme.BUTTON_LINK);
            b.setWidth("60px");
            b.addListener(new Button.ClickListener() {
                public void buttonClick(Button.ClickEvent clickEvent) {
                    final String path = getApplication().getURL().getPath();
                    getApplication().getMainWindow().open(
                            new ExternalResource(path + "login"));
                }
            }); // react to clicks
            cssLayout.addComponent(b);
            cssLayout.setComponentAlignment(b, Alignment.MIDDLE_LEFT);
        } else {
            Label userName = new Label(currentUserName());
            userName.setWidth("130px");
            cssLayout.addComponent(userName);
            cssLayout.setComponentAlignment(userName, Alignment.MIDDLE_LEFT);
        }
        if (hasAnyRole(ROLE_USER)) {
            Button logout = new Button("Loguot");
            logout.setStyleName(BaseTheme.BUTTON_LINK);
            logout.setWidth("60px");
            logout.addListener(new Button.ClickListener() {
                private static final long serialVersionUID = 1L;

                public void buttonClick(Button.ClickEvent clickEvent) {
                    LoguotWindow loguotWindow = new LoguotWindow("", "Are you sure?");
                    getApplication().getMainWindow().addWindow(loguotWindow);
                }
            });
            cssLayout.addComponent(logout);
            cssLayout.setComponentAlignment(logout, Alignment.MIDDLE_LEFT);
        }
        hLayout.addComponent(cssLayout);
        hLayout.setComponentAlignment(cssLayout, Alignment.MIDDLE_RIGHT);
        addComponent(hLayout);
    }

    public boolean hasAnyRole(String... roles) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Collection authorities = (Collection) authentication.getAuthorities();
        for (GrantedAuthority authority : authorities) {
            for (String role : roles) {
                if (role.equals(authority.getAuthority())) {
                    return true;
                }
            }
        }
        return false;
    }

    public String currentUserName() {
        return SecurityContextHolder.getContext().getAuthentication().getName();
    }
}
При завершении работы пользователя в Vaadin мы должны очистить асоциированные данные с ним посредством вызова метода getApplication().close(); и предупредить Spring что мы сделали "Logout".
package com.vit;

import com.vaadin.ui.*;

public class LoguotWindow extends Window {

    public VerticalLayout vLayout;
    public Label qLabel;
    public HorizontalLayout hLayout;
    public Button close;
    public Button closeWindow;

    public LoguotWindow(String caption, String qCaption) {
        super(caption);
        center();
        setImmediate(true);
        setClosable(true);
        setModal(true);
        setWidth("200px");
        setHeight("200px");
        setScrollable(false);
        vLayout = new VerticalLayout();
        vLayout.setSpacing(true);
        vLayout.setSizeFull();
        qLabel = new Label(qCaption);
        vLayout.addComponent(qLabel);
        hLayout = new HorizontalLayout();
        hLayout.setSpacing(true);
        close = new Button("YES", new Button.ClickListener() {
            private static final long serialVersionUID = 1L;

            public void buttonClick(Button.ClickEvent event) {
                // close the window by removing it from the parent window
                getApplication().close();
                getParent().removeWindow(getWindow());
            }
        });
        hLayout.addComponent(close);
        closeWindow = new Button("NO", new Button.ClickListener() {
            private static final long serialVersionUID = 1L;

            public void buttonClick(Button.ClickEvent event) {
                // close the window by removing it from the parent window
                getParent().removeWindow(getWindow());
            }
        });
        hLayout.addComponent(closeWindow);
        vLayout.addComponent(hLayout);
        hLayout.setSizeFull();
        vLayout.setComponentAlignment(hLayout, Alignment.MIDDLE_CENTER);
        addComponent(vLayout);
    }
}
При вызове метода getApplication().close(); Vaadin делает redirect по методу setLogoutURL(getURL().getPath() + "j_spring_security_logout"); который дает понят Spring'у что пользователь вышел и спринг "удаляет" все данные связанные с пользователем, в свою очередь он делает redirect в корень / web приложения вот и все:
public class MyVaadinApplication extends Application {
    private Window window;
    public Button button;
    private HeadPanel headPanel;
    @Autowired(required = true)
    private TestBean testBean;

    @Override
    public void init() {
        setTheme("runo");
        window = new Window("Hello Vaadin!");
        setMainWindow(window);
        setLogoutURL(getURL().getPath() + "j_spring_security_logout");
        window.setImmediate(true);

        headPanel = new HeadPanel();
        headPanel.setSizeFull();
        window.addComponent(headPanel);
        Button button = new Button("Click Me");
        button.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                if (headPanel.hasAnyRole(ROLE_USER)) {
                    Label label = new Label("you are ROLE_USER");
                    window.addComponent(label);
                } else {
                    Label label = new Label("you are not Login");
                    window.addComponent(label);
                }
            }
        });
        window.addComponent(button);
    }
}
Привожу pom.xml c зависимостями
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.vit</groupId>
    <artifactId>VaadinTest11</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Vaadin Web Application</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <vaadin.version>6.6.6</vaadin.version>
        <gwt.version>2.3.0</gwt.version>
        <gwt.plugin.version>2.2.0</gwt.plugin.version>
        <spring.version>3.1.1.RELEASE</spring.version>
        <spring-security.version>3.1.0.RELEASE</spring-security.version>
    </properties>

    <build>
        <finalName>test</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!-- A simple Jetty test server at http://localhost:8080/VaadinTest11 can be launched with the Maven goal jetty:run
        and stopped with jetty:stop -->
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.24</version>
                <configuration>
                    <stopPort>9966</stopPort>
                    <stopKey>VaadinTest11</stopKey>
                    <!-- Redeploy every x seconds if changes are detected, 0 for no automatic redeployment -->
                    <scanIntervalSeconds>0</scanIntervalSeconds>
                    <!-- make sure Jetty also finds the widgetset -->
                    <webAppConfig>
                        <contextPath>/VaadinTest11</contextPath>
                        <baseResource implementation="org.mortbay.resource.ResourceCollection">
                            <!-- Workaround for Maven/Jetty issue http://jira.codehaus.org/browse/JETTY-680 -->
                            <!-- <resources>src/main/webapp,${project.build.directory}/${project.build.finalName}</resources> -->
                            <resourcesAsCSV>src/main/webapp,${project.build.directory}/${project.build.finalName}
                            </resourcesAsCSV>
                        </baseResource>
                    </webAppConfig>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>vaadin-snapshots</id>
            <url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>vaadin-addons</id>
            <url>http://maven.vaadin.com/vaadin-addons</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin</artifactId>
            <version>${vaadin.version}</version>
        </dependency>

        <!-- Spring Dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <type>jar</type>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-support</artifactId>
            <version>2.0.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.xbean</groupId>
            <artifactId>xbean-spring</artifactId>
            <version>3.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.6.6</version>
        </dependency>

        <!-- http://repo1.maven.org/maven -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.1</version>
        </dependency>
        <!--spring-security-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring-security.version}</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring-security.version}</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring-security.version}</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring-security.version}</version>
            <type>jar</type>
        </dependency>
    </dependencies>

</project>

10.11.2012

Vaadin и Spring @Autowired.

Здесь я хочу познокомить вас с еще одной моей наработкой, а именно как я подключаю  Spring фраемворк к Vaadin. И так начнем с создания простейшего bean'а который возврашает нам Spring, а у него метод public String getTestString() возвращает нам простую строчку
"  -= TestString SPRING =- ", сначало опишим его interface:
package com.vit.bean;

public interface TestBean {
    public String getTestString();
} 
потом его реализацию:
package com.vit.bean;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component("test")
@Scope(value = "prototype")
public class TestBeanImpl implements TestBean{

    public String getTestString() {
        return "  -= TestString SPRING =- ";
    }
} 
Далее нам нужно описать класс сервлет который будет инжектить наши бины в компоненты Vaadin'е.
package com.vit;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.ApplicationServlet;

public class AutowiringApplicationServlet extends ApplicationServlet {
 private static final long serialVersionUID = 1L;
 private WebApplicationContext webApplicationContext;

 @Override
 public void init(ServletConfig config) throws ServletException {
  super.init(config);
  try {
   this.webApplicationContext = WebApplicationContextUtils.
                    getRequiredWebApplicationContext(config.getServletContext());
  } catch (IllegalStateException e) {
   throw new ServletException("could not locate containing WebApplicationContext");
  }
 }

 protected final WebApplicationContext getWebApplicationContext() throws ServletException {
  if (this.webApplicationContext == null)
   throw new ServletException("can't retrieve WebApplicationContext before init() is invoked");
  return this.webApplicationContext;
 }

 protected final AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws ServletException {
  try {
   return getWebApplicationContext().getAutowireCapableBeanFactory();
  } catch (IllegalStateException e) {
   throw new ServletException("containing context " + getWebApplicationContext() + " is not autowire-capable", e);
  }
 }

 @Override
 protected Application getNewApplication(HttpServletRequest request) throws ServletException {
  Class cl = null;
  try {
   cl = getApplicationClass();
  } catch (ClassNotFoundException e1) {
   e1.printStackTrace();
  }
  AutowireCapableBeanFactory beanFactory = getAutowireCapableBeanFactory();
  try {
   return beanFactory.createBean(cl);
  } catch (BeansException e) {
   throw new ServletException("failed to create new instance of " + cl, e);
  }
 }
} 
после этого нужно настроить все в web.xml что бы обработка шла через наш сервлет:
<servlet>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <servlet-class>com.vit.AutowiringApplicationServlet</servlet-class>
        <init-param>
            <param-name>application</param-name>
            <param-value>com.vit.MyVaadinApplication</param-value>
        </init-param>
    </servlet>
описывать настройку Spring'a для веб не буду просто приведу полный листинг web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
    <display-name>Vaadin Web Application</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
        </param-value>
    </context-param>

    <servlet>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <servlet-class>com.vit.AutowiringApplicationServlet</servlet-class>
        <init-param>
            <param-name>application</param-name>
            <param-value>com.vit.MyVaadinApplication</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

</web-app>
в файле конфигурации Spring делаю минимальные настройки для работы аннотаций:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:beans="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
                           http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <context:annotation-config />
    <!-- Turn on AspectJ @Configurable support -->
    <!--<context:spring-configured/>-->
    <context:component-scan base-package="com.vit.bean"/>
    <!-- Turn on @Autowired, @PostConstruct etc support -->
 <beans:bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
 <beans:bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

</beans>
Собственно осталось только привести тело основной программы:
package com.vit;

import com.vaadin.Application;
import com.vaadin.data.Property;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.Runo;
import com.vit.bean.TestBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;

@SuppressWarnings("serial")
@Configurable(preConstruction = true, dependencyCheck = true)
public class MyVaadinApplication extends Application {
    private Window window;
    public Button button;
    @Autowired(required = true)
    private TestBean testBean;

    @Override
    public void init() {
        setTheme("runo");
        window = new Window("Hello Vaadin!");
        setMainWindow(window);
        window.setImmediate(true);
        button = new Button("Button.text");
        button.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                window.addComponent(new Label("Label.text"+testBean.getTestString()));
            }
        });
        button.addStyleName(Runo.BUTTON_SMALL);
        window.addComponent(button);
    }
} 
в строчке мы уже имем любездно созданный Spring'om бин @Autowired(required = true) private TestBean testBean; в строчке new Label("Label.text"+testBean.getTestString()) вызываем getTestString() который возвращает нам строку " -= TestString SPRING =- " Спринг дает нам новые возможности по использованию Vaadin'a и через него мы можем подключить какие угодно вкусности типа Hibernate, Mybatis, JDBC and etc ... Осталось в этой статье только привести зависимости maven'a:
 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.vit</groupId>
  <artifactId>VaadinTest11</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Vaadin Web Application</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <vaadin.version>6.6.6</vaadin.version>
    <gwt.version>2.3.0</gwt.version>
    <gwt.plugin.version>2.2.0</gwt.plugin.version>
    <spring.version>3.1.1.RELEASE</spring.version>
  </properties>

  <build>
    <finalName>test</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

      <!-- A simple Jetty test server at http://localhost:8080/VaadinTest11 can be launched with the Maven goal jetty:run 
        and stopped with jetty:stop -->
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
        <version>6.1.24</version>
        <configuration>
          <stopPort>9966</stopPort>
          <stopKey>VaadinTest11</stopKey>
          <!-- Redeploy every x seconds if changes are detected, 0 for no automatic redeployment -->
          <scanIntervalSeconds>0</scanIntervalSeconds>
          <!-- make sure Jetty also finds the widgetset -->
          <webAppConfig>
            <contextPath>/VaadinTest11</contextPath>
            <baseResource implementation="org.mortbay.resource.ResourceCollection">
              <!-- Workaround for Maven/Jetty issue http://jira.codehaus.org/browse/JETTY-680 -->
              <!-- <resources>src/main/webapp,${project.build.directory}/${project.build.finalName}</resources> -->
              <resourcesAsCSV>src/main/webapp,${project.build.directory}/${project.build.finalName}</resourcesAsCSV>
            </baseResource>
          </webAppConfig>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>vaadin-snapshots</id>
      <url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>vaadin-addons</id>
      <url>http://maven.vaadin.com/vaadin-addons</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>com.vaadin</groupId>
      <artifactId>vaadin</artifactId>
      <version>${vaadin.version}</version>
    </dependency>
    <!-- Spring Dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <type>jar</type>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-support</artifactId>
            <version>2.0.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
      <!-- logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.xbean</groupId>
            <artifactId>xbean-spring</artifactId>
            <version>3.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.6.6</version>
        </dependency>

      <!-- http://repo1.maven.org/maven -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.1</version>
        </dependency>
  </dependencies>

</project>