📜 ⬆️ ⬇️

ZK + Spring 3 + Hibernate: two heads are good, but three is better, faster, stronger

Good day to all. So I decided to share how to combine the two monsters of the Spring Framework and Hibernate with the powerful j2ee framework ZK . For a start, why exactly ZK, and not GWT or even a native jsp? Because (purely subjective) ZK has the most painless integration with these frameworks, and generally I haven’t found it easier yet, I’ll try to prove it to you.
My example will be simple, since my goal is to show how to make all these frameworks work, and with the least headache. For the database, take Oracle. And we will write a simple web application that will display user names. Also, in order to show the power and simplicity of ZK, let's add a bit of functionality, for example, deleting users from the system and editing its name.

The first thing we need to do is create a ZK project (an option appears only after installing the plug-in in Eclipse), or just a dynamic web project, the difference is in the generated web.xml file, in the index.zul, timeout.zul, zk.xml and in the framework libraries that will be automatically added.
Since our application will be built on the MVC pattern, we first describe the model. Create in the src folder a mapping table called Person, which should be in our Oracle schema:
package com.sample.data; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "PERSON") public class Person implements Serializable { private static final long serialVersionUID = 4624748294368212545L; @Id private long id; @Column(name = "Name") private String personName; public Person() { } public Person(long id, String personName) { super(); this.id = id; this.personName = personName; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getPersonName() { return personName; } public void setPersonName(String personName) { this.personName = personName; } } 

The next step is to determine what we will do with this class: display the collection and edit the user name. We describe the interface for accessing our class:
 package com.sample.service; import java.util.List; import com.sample.data.Person; public interface IPerson { List<Person> findAllPerson(); boolean delete(Person pers); boolean saveOrUpdate(Person person); } 

and of course the implementation:

 package com.sample.service; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.criterion.Restrictions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.sample.data.Person; @Repository @Transactional(readOnly = true) public class PersonImpl implements IPerson { private static SessionFactory sessionFactory; //  datasource @Autowired public void setSessionFactory(SessionFactory sessionFactory) { PersonImpl.sessionFactory = sessionFactory; } @SuppressWarnings("unchecked") @Override @Transactional(readOnly = true, propagation = Propagation.REQUIRED) public List<Person> findAllPerson() { Session session = sessionFactory.getCurrentSession(); return (List<Person>) session.createQuery("from Person").list(); } @Override @Transactional(readOnly = false, propagation = Propagation.REQUIRED) public boolean delete(Person pers) { try { Session session = sessionFactory.getCurrentSession(); session.delete(pers); return true; } catch (Exception e) { return false; } } @Override @Transactional(readOnly = false, propagation = Propagation.REQUIRED) public boolean saveOrUpdate(Person person) { try { Session session = sessionFactory.getCurrentSession(); session.saveOrUpdate(person); return true; } catch (Exception e) { return false; } } } 

As can be seen from the code of the PersonImpl class, we placed the work with transactions, the connection to the database on the shoulders of Spring, and all CRUD actions will be performed by hibernate.
Adhering to the MVC ideology, we describe the controller. In ZK, this is done in several ways, I will describe the simplest one - inheritance from the Window class:

 package ui.component; import java.util.List; import javax.servlet.ServletContext; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import org.zkoss.zul.Listbox; import org.zkoss.zul.Listitem; import org.zkoss.zul.Messagebox; import org.zkoss.zul.Textbox; import org.zkoss.zul.Toolbarbutton; import org.zkoss.zul.Window; import com.sample.data.Person; import com.sample.service.IPerson; public class PersonInfo extends Window { private static final long serialVersionUID = -6186588639173052172L; //     persons    private Listbox personListBox; private Toolbarbutton tbbDelete; private List<Person> personList; private IPerson dao; private Textbox tbPersonName; private Toolbarbutton tbbSave; //  ,       public void onCreate() { //    ApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext((ServletContext) getDesktop().getWebApp().getNativeContext()); //   dao = (IPerson) ctx.getBean("personImpl"); personList = dao.findAllPerson(); tbPersonName = (Textbox) this.getFellow("tbPersonName"); tbbSave = (Toolbarbutton) this.getFellow("tbbSave"); if (personList.size() > 0) { //     - personListBox = (Listbox) this.getFellow("lbPerson"); tbbDelete = (Toolbarbutton) this.getFellow("tbbDelete"); //    populateListBox(); } } private void populateListBox() { for (Person pers : personList) { personListBox.appendChild(new Listitem(pers.getPersonName(), pers)); } } //    @SuppressWarnings("unchecked") public void onDeletePerson() { for (Listitem li : (List<Listitem>) personListBox.getItems()) { if (li.isSelected()) { if (dao.delete((Person) li.getValue())) { //    personList.remove((Person) li.getValue()); personListBox.removeChild(li); } } } } //   ,      public void onSelectLB() { if (personListBox.getSelectedCount() > 0) { tbbDelete.setDisabled(false); tbbSave.setDisabled(true); tbPersonName.setValue(((Person) personListBox.getSelectedItem().getValue()).getPersonName()); } else { tbbDelete.setDisabled(true); } } //   public void onSave() throws InterruptedException { if (tbPersonName.getValue() != null && tbPersonName.getValue().trim().length() > 0) { Person pers = (Person) personListBox.getSelectedItem().getValue(); pers.setPersonName(tbPersonName.getValue().trim()); if (!dao.saveOrUpdate(pers)) { Messagebox.show("      "); } else { personListBox.getSelectedItem().setLabel(pers.getPersonName()); personListBox.getSelectedItem().setValue(pers); } } else { Messagebox.show(" \"\"    "); } } } 

We now turn to the configuration files. Let's start with the context of the connection to the database, namely setting the Connection Pool. Create a context.xml file in the META-INF folder with the following text:
 <?xml version="1.0" encoding="UTF-8"?> <!-- JDBC --> <Context path="/db1" docBase="db1" debug="5" reloadable="true" crossContext="true"> <Resource name="jdbc/taskdb" username="test" password="test" url="jdbc:oracle:thin:@localhost:1521:test" auth="Container" defaultAutoCommit="false" driverClassName="oracle.jdbc.driver.OracleDriver" maxActive="2" maxIdle="10" maxWait="-1" timeBetweenEvictionRunsMillis="60000" testOnBorrow="true" testWhileIdle="true" queryTimeout="20000" validationQueryTimeout="2" initialSize="1" removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true" type="javax.sql.DataSource" /> </Context> 

since we used annotations for mapping to the Person table, we will create a hibernate.cfg.xml file in the WEB-INF folder, in which we specify our class:
 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <mapping class="com.sample.data.Person" /> </session-factory> </hibernate-configuration> 

Let's create a spring configuration file, in which we will describe the context of the Oracle connection using jndi, bean sessionFactory, hibernate configuration and the package that spring should look at in order to apply annotations. Create a spring-config.xml file in the WEB-INF folder:
 <?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:tx="http://www.springframework.org/schema/tx" 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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <context:annotation-config /> <context:component-scan base-package="com.sample" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>java:comp/env/jdbc/taskdb</value> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="dataSource" ref="dataSource" /> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource" /> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop> <prop key="hibernate.show_sql">false</prop> </props> </property> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> <property name="configLocation" value="/WEB-INF/hibernate.cfg.xml" /> </bean> </beans> 

Now come the turn of web.xml. In it, in addition to the ZK settings, you will need to specify a listener for spring, and the path of the spring and hibernate configuration files:
 <?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>zkSpringHibernate</display-name> <listener> <description> Used to cleanup when a session is destroyed</description> <display-name>ZK Session cleaner</display-name> <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class> </listener> <servlet> <description> The ZK loader for ZUML pages</description> <servlet-name>zkLoader</servlet-name> <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class> <init-param> <param-name>update-uri</param-name> <param-value>/zkau</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet> <description> The asynchronous update engine for ZK</description> <servlet-name>auEngine</servlet-name> <servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>zkLoader</servlet-name> <url-pattern>*.zul</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>zkLoader</servlet-name> <url-pattern>*.zhtml</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>auEngine</servlet-name> <url-pattern>/zkau/*</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> </session-config> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-config.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>hibernateFilter</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.zul</welcome-file> </welcome-file-list> </web-app> 

The next link is a view, again based on MVC terminology. We describe our web application with zul markup (file index.zul, path -WebContent):

 <?page title="ZK integration"?> <window title="view person" border="normal" width="100%" id="wndViewPerson" use="ui.component.PersonInfo"> <listbox id="lbPerson" hflex="1" vflex="1" checkmark="true" emptyMessage="data not found" onSelect="wndViewPerson.onSelectLB()"> <listhead> <listheader label="" /> </listhead> </listbox> <hlayout> <label value="" /> <textbox width="150px" id="tbPersonName" onChanging="tbbSave.setDisabled(false)" /> <toolbarbutton label="save" onClick="wndViewPerson.onSave()" id="tbbSave" disabled="true" /> <toolbarbutton label="delete" disabled="true" id="tbbDelete" onClick="wndViewPerson.onDeletePerson()" /> </hlayout> </window> 

One small clarification, in the configuration file zk.xml, which should be located in the WEB-INF folder, we indicate the class responsible for serialization:
 <?xml version="1.0" encoding="UTF-8"?> <zk> <system-config> <ui-factory-class> org.zkoss.zk.ui.http.SerializableUiFactory </ui-factory-class> </system-config> </zk> 

Now that's all, pay attention to how easy, convenient and most importantly without intermediate links and crutches, you can work with the refcursor, and in general with the database.
And this is the minimum list of libraries needed to run the application:

PS I hope everyone will start, but if not, then write, send a project. And yet, if this article seemed interesting to you, and I would also like to know about the ZK framework itself, or about integration, for example, with Spring Security, then let me know.

')

Source: https://habr.com/ru/post/129189/


All Articles