Once we create our core workspace as explained in Last artical. Now we will create few core components that will form the bases of any project that operates of data exposed by this project or maintains various operations on this DB. So now we create our spring configuration file countries-app-context.xml as shown below.
As one can notice this configuration only contains core information. Information specific to each module will be moved to separate config file. For an example information about the db will be maintained in separate configuration file called countries-jpa-context.xml as follows
Once this structure is created let's at high level decide what we need to create. We have total 3 entities Country, City and Country Language so for these three entities (to make it simple one to one relationship between DB table and a java bean) we need to create three java beans. To access these beans we need to have a repository and to use that repository and perform some business logic we need to have a service class. Last but not the least to test the entire flow we will need our JUnit classes.
So first lets start with creating interfaces, in the next step we will create test cases in Junit based on DB information we have and once that is ready we will create implementation classes. In each service interface we will have 2 methods first method will find a record by primary key and second method will find records by one of column value for table. So following will be the structure.
For simplicity we will create flow for only one entity (country) and interested user can do the same for City. CountryLanguage has some special scenario that we will cover in later tutorials. First we will create a bean class for country
Next we create service interface as shown below.
Now create a test case.
So once we have the test case ready we will do the actual development (not quite common but this is how TDD or Test Driven Development suppose to work). First we create a repository interface which will extend JpaRepository
Next we will create service implementation and repository. Service implementation will be as shown below.
Few cool features of repository are
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<beans xmlns="http://www.springframework.org/schema/beans" | |
xmlns:context="http://www.springframework.org/schema/context" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd | |
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> | |
<context:annotation-config/> | |
<context:component-scan base-package="com.techcielo.sphr.core"/> | |
<import resource="classpath:country-jpa-context.xml"/> | |
</beans> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<beans xmlns="http://www.springframework.org/schema/beans" | |
xmlns:jpa="http://www.springframework.org/schema/data/jpa" | |
xmlns:context="http://www.springframework.org/schema/context" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd | |
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd | |
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> | |
<jpa:repositories base-package="com.techcielo.sphr.core.repo" | |
entity-manager-factory-ref="entityManagerFactory" | |
transaction-manager-ref="transactionManager"/> | |
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> | |
<property name="entityManagerFactory" ref="entityManagerFactory" /> | |
</bean> | |
<bean id="entityManagerFactory" | |
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> | |
<property name="dataSource" ref="dataSource" /> | |
<property name="packagesToScan" value="com.techcielo.sphr.core.bean" /> | |
<property name="jpaVendorAdapter"> | |
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> | |
<property name="showSql" value="true"/> | |
</bean> | |
</property> | |
</bean> | |
<bean id="dataSource" | |
class="org.springframework.jdbc.datasource.DriverManagerDataSource"> | |
<property name="driverClassName" value="com.mysql.jdbc.Driver" /> | |
<property name="url" value="jdbc:mysql://localhost/world_db" /> | |
<property name="username" value="root" /> | |
<property name="password" value="" /> | |
</bean> | |
</beans> |
So first lets start with creating interfaces, in the next step we will create test cases in Junit based on DB information we have and once that is ready we will create implementation classes. In each service interface we will have 2 methods first method will find a record by primary key and second method will find records by one of column value for table. So following will be the structure.
For simplicity we will create flow for only one entity (country) and interested user can do the same for City. CountryLanguage has some special scenario that we will cover in later tutorials. First we will create a bean class for country
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.techcielo.sphr.core.bean; | |
import javax.persistence.Entity; | |
import javax.persistence.Id; | |
import javax.persistence.Table; | |
@Entity | |
@Table(name="Country") | |
public class CountryBean { | |
@Id | |
private String code; | |
private String name; | |
private Double gnp; | |
public String getCode() { | |
return code; | |
} | |
public void setCode(String code) { | |
this.code = code; | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public Double getGnp() { | |
return gnp; | |
} | |
public void setGnp(Double gnp) { | |
this.gnp = gnp; | |
} | |
} |
Next we create service interface as shown below.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.techcielo.sphr.core.service; | |
import java.util.List; | |
import com.techcielo.sphr.core.bean.CountryBean; | |
public interface CountryService { | |
public CountryBean getCountryByCode(String code); | |
public List<CountryBean> findCountryByGnp(Double gnp); | |
} |
Now create a test case.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.techcielo.sphr.core.test; | |
import java.util.List; | |
import org.springframework.context.ApplicationContext; | |
import org.springframework.context.support.ClassPathXmlApplicationContext; | |
import com.techcielo.sphr.core.bean.CountryBean; | |
import com.techcielo.sphr.core.service.CountryService; | |
import junit.framework.TestCase; | |
public class CountryServiceTest extends TestCase{ | |
ApplicationContext ctx = new ClassPathXmlApplicationContext("countries-app-context.xml"); | |
public void testFindSingle(){ | |
CountryService svc = ctx.getBean(CountryService.class); | |
CountryBean country = svc.getCountryByCode("IND"); | |
assertNotNull(country); | |
assertEquals("India", country.getName()); | |
} | |
public void testFindByColumn(){ | |
CountryService svc = ctx.getBean(CountryService.class); | |
List<CountryBean> countryList = svc.findCountryByGnp(50000.0); | |
assertNotNull(countryList); | |
assertEquals(51,countryList.size()); | |
} | |
} |
So once we have the test case ready we will do the actual development (not quite common but this is how TDD or Test Driven Development suppose to work). First we create a repository interface which will extend JpaRepository
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.techcielo.sphr.core.repo; | |
import java.util.List; | |
import org.springframework.data.jpa.repository.JpaRepository; | |
import com.techcielo.sphr.core.bean.CountryBean; | |
public interface CountryRepo extends JpaRepository<CountryBean, String>{ | |
public CountryBean findByCode(String code); | |
public List<CountryBean> findByGnpGreaterThan(Double gnp); | |
} |
Next we will create service implementation and repository. Service implementation will be as shown below.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.techcielo.sphr.core.service.impl; | |
import java.util.List; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Service; | |
import com.techcielo.sphr.core.bean.CountryBean; | |
import com.techcielo.sphr.core.repo.CountryRepo; | |
import com.techcielo.sphr.core.service.CountryService; | |
@Service | |
public class CountryServiceImpl implements CountryService{ | |
@Autowired | |
CountryRepo repo; | |
public CountryBean getCountryByCode(String code) { | |
return repo.findByCode(code); | |
} | |
public List<CountryBean> findCountryByGnp(Double gnp) { | |
return repo.findByGnpGreaterThan(gnp); | |
} | |
} |
- They are interface and DO NOT PROVIDE IMPLEMENTATION FOR THEM.
- You need to follow just convention of defining your method name in interface.
- findByCode will result in query "SELECT * FROM COUNTRY WHERE Code=?"
- findByGnpGreaterThan will result in "SELECT * FROM COUNTRY WHERE gnp>?"
Now run your test case and following will be the output.
Following log is for reference.
2015/08/15T01:11:28,231 DEBUG [org.jboss.logging] [<clinit>] - Logging Provider: org.jboss.logging.Log4jLoggerProvider
2015/08/15T01:11:29,565 WARN [org.hibernate.jpa.internal.EntityManagerFactoryRegistry] [addEntityManagerFactory] - HHH000436: Entity manager factory name (default) is already registered. If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'
Hibernate: select countrybea0_.code as code1_0_, countrybea0_.gnp as gnp2_0_, countrybea0_.name as name3_0_ from Country countrybea0_ where countrybea0_.gnp>?
Hibernate: select countrybea0_.code as code1_0_, countrybea0_.gnp as gnp2_0_, countrybea0_.name as name3_0_ from Country countrybea0_ where countrybea0_.code=?