Pom.xml file:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback-version}</version>
</dependency>
In src/main/resources folder, create logback.xml file. Put these configuration:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration>
<!-- File appender -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>D:\mmt-ws-logs\mmt-ws-log.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>D:\mmt-ws-logs\mmt-ws-log.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{ISO8601} [%-5p] [%t] %c %X - %m%n</pattern>
</encoder>
</appender>
<!-- Console appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<pattern>%d{HH:mm:ss} %level [%thread] %logger [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<root level="INFO,ERROR">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
In this case, we use RollingFileAppender to write log to file. It also recreate new file for new date.
For showing in Console, use ConsoleAppender.
Wednesday, December 31, 2014
Tuesday, December 30, 2014
Sequence in Oracle
Create Sequence
CREATE SEQUENCE customers_seq
START WITH 1000
INCREMENT BY 1
NOCACHE
NOCYCLE;
In case that we already have data in DB, use this snippet:
declare
new_id number;
begin
select NVL(max(id),0) + 1
into new_id
from my_table;
execute immediate 'Create sequence my_seq
start with ' || new_id ||
' increment by 1';
end;
/
Use Sequence
In Entity object:/** The auto id. */
private Long autoId;
/**
* Gets the auto id.
*
* @return the auto id
*/
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sq")
@SequenceGenerator(name = "sq", sequenceName = "my_seq", allocationSize=1)
@Column(name = "AUTOID", unique = true, nullable = false, precision = 30, scale = 0)
public Long getAutoId() {
return this.autoId;
}
/**
* Sets the auto id.
*
* @param autoId the new auto id
*/
public void setAutoId(Long autoId) {
this.autoId = autoId;
}
GenerationType.SEQUENCE is specific for Oracle. Because Oracle uses Sequence strategy for create AutoId.
In @SequenceGenerator, the “allocationSize” is by default set to 50
And, by default, the “increment by” is set to 1.
Note:
It’s important to note that, the sequence generator work correctly, only when the “allocationSize” and the “increment by” are same, otherwise there is a possibility of getting the “unique constraint violation” exception. therefore, it is better to explicitly define “allocationSize” and “increment by”.Monday, December 29, 2014
Get package version from MANIFEST file
In pom.xml, specify default ImplementationEntries and SpecificationEntries as below:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<Implementation-Version>${project.version}</Implementation-Version>
</manifestEntries>
</archive>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
These fields will be automatically added to MANIFEST file.
In Java class, use this snippet to read value:
@Override
public BuildVersion getVersion() throws IOException {
Package p = this.getClass().getPackage();
BuildVersion buildVersion = new BuildVersion();
buildVersion.setBuildName(p.getImplementationTitle());
buildVersion.setVersion(p.getImplementationVersion());
return buildVersion;
}
(BuildVersion is a custom class that contains result.)
Note: war file has to be put in server. At that time manifest file will be available to read properly.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<Implementation-Version>${project.version}</Implementation-Version>
</manifestEntries>
</archive>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
These fields will be automatically added to MANIFEST file.
In Java class, use this snippet to read value:
@Override
public BuildVersion getVersion() throws IOException {
Package p = this.getClass().getPackage();
BuildVersion buildVersion = new BuildVersion();
buildVersion.setBuildName(p.getImplementationTitle());
buildVersion.setVersion(p.getImplementationVersion());
return buildVersion;
}
(BuildVersion is a custom class that contains result.)
Note: war file has to be put in server. At that time manifest file will be available to read properly.
Thursday, December 25, 2014
Create Index and using Index hints
CREATE INDEX:
There are many types of index introduced by Oracle.http://docs.oracle.com/cd/B19306_01/server.102/b14231/indexes.htm
Each type have the different way to create. Ex:
CREATE INDEX programId_index ON PROGRAM(programId) COMPUTE STATISTICS;
Put Index on columns that appear in WHERE statement.
Good for single column - one index.
Can put multi-columns in index but make sure that the all these columns appear in WHERE statement. If not, index does not help.
Ex: CREATE INDEX User_index ON PROGRAM(firstName, lastName, title) COMPUTE STATISTICS;
Great if: SELECT * from User WHERE firstName = ? AND lastName = ?
Bad if: SELECT * from User WHERE lastName = ?
or SELECT * from User WHERE lastName = ? AND title = ?
Index will make DML (insert, update, delete) slow down (3-time slower than the table with no indexes). Should not index on column that value is too much duplicated.
INDEX HINTS:
Use Hints indicate Oracle using index:SELECT /*+ index(table_name(column_has_indexed)) */ * FROM customer;
Oracle Semi-Joins and Anti-Joins
Using EXISTS and IN.
Example 1:
SELECT D.deptno, D.dname FROM dept D, emp E WHERE E.deptno = D.deptno ORDER BY D.deptno;
Change to:
SELECT D.deptno, D.dname FROM dept D WHERE EXISTS ( SELECT 1 FROM emp E WHERE E.deptno = D.deptno ) ORDER BY D.deptno;
Example 2:
SELECT D1.deptno, D1.dname FROM dept D1 MINUS SELECT D2.deptno, D2.dname FROM dept D2, emp E2 WHERE D2.deptno = E2.deptno ORDER BY 1;
Change to:
SELECT D.deptno, D.dname FROM dept D WHERE NOT EXISTS ( SELECT 1 FROM emp E WHERE E.deptno = D.deptno ) ORDER BY D.deptno;
References:
http://www.dbspecialists.com/files/presentations/semijoins.html
Sunday, December 14, 2014
RestTemplate cannot map a single object to a list
ResponseEntity<String> response =
restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
resObject = mapper.readValue(response.getBody(),
ResponseObject.class);
The problem is that if ResponseObject in server side has only one item set to a list, by default, JAXB will convert this list to a single json object (not an array contains one object as we expected) so the mapper in client side cannot map correctly.
Solution 1: by code
List converters =
restTemplate.getMessageConverters();
for (Object converter : converters) {
if (converter instanceof MappingJacksonHttpMessageConverter) {
MappingJacksonHttpMessageConverter jconverter =
(MappingJacksonHttpMessageConverter) converter;
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(
DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY,
true);
jconverter.setObjectMapper(mapper);
}
}
Solution 2: by XML configuration:
<!-- Jackson Mapper -->
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="jacksonObjectMapper" />
<property name="targetMethod" value="configure" />
<property name="arguments">
<list>
<value type="org.codehaus.jackson.map.DeserializationConfig.Feature">FAIL_ON_UNKNOWN_PROPERTIES</value>
<value>false</value>
</list>
</property>
</bean>
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
Hope that helps.
References:
http://stackoverflow.com/questions/14343477/how-do-you-globally-set-jackson-to-ignore-unknown-properties-within-spring
Friday, December 12, 2014
Jersey Test
pom.xml
<!-- Jersey --><dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>1.8</version>
<scope>test</scope>
</dependency>
Test class:
public class MyClassTest extends JerseyTest {@Override
public AppDescriptor configure() {
return new WebAppDescriptor.Builder("com.example.person.endpoint")
.servletClass(SpringServlet.class)
.contextParam("contextConfigLocation", "classpath:context/endpointIntegrationContext.xml")
.contextListenerClass(ContextLoaderListener.class)
.contextPath("test-project").build();
}
@Before
public void setUp() {
mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
}
@After
public void tearDown() {
}
@Test
public void testGetByUserId() throws Exception {
RestTemplate restTemplate = new RestTemplate();
Long userId = 1L;
String endpoint = getBaseURI() + "test-project/person/getByUserId/{userId}";
final Map<String, Object> urlParameter = new HashMap<String, Object>();
urlParameter.put("userId", userId);
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(endpoint, HttpMethod.GET, entity, String.class, urlParameter);
responseEntity.getBody()
//...
}
Thursday, December 11, 2014
Using Spring Data JPA
Spring Data JPA is a library / framework that adds an extra layer of abstraction on the top of our JPA provider.
DAO Structure
Configuration:
<?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:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
">
<!-- Enables the Spring MVC @Controller programming model -->
<mvc:annotation-driven />
<jpa:repositories base-package="com.journaldev.spring.repository"/>
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/spring-data-jpa" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<!-- spring based scanning for entity classes-->
<property name="packagesToScan" value="com.journaldev.spring.model"/>
</bean>
<bean id="personDAO" class="com.journaldev.spring.dao.PersonDAOImpl">
<property name="em" ref="entityManagerFactory" />
</bean>
<bean id="personService" class="com.journaldev.spring.service.PersonServiceImpl">
<property name="personDAO" ref="personDAO"></property>
</bean>
<context:component-scan base-package="com.journaldev.spring" />
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Usage:
import org.springframework.data.jpa.repository.JpaRepository;
import com.journaldev.spring.model.Person;
public interface PersonRepository extends JpaRepository<Person, Integer> {
}
Add to where to use:
@Autowired
private PersonRepository personRepository;
To add function to JpaRepository, we have 3 ways:
* Declare method name by combine keyword and fieldName
* Using NamedQuery
DAO Structure
Using JpaRepository and Entity Manager persistence |
Configuration:
<?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:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
">
<!-- Enables the Spring MVC @Controller programming model -->
<mvc:annotation-driven />
<jpa:repositories base-package="com.journaldev.spring.repository"/>
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/spring-data-jpa" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<!-- spring based scanning for entity classes-->
<property name="packagesToScan" value="com.journaldev.spring.model"/>
</bean>
<bean id="personDAO" class="com.journaldev.spring.dao.PersonDAOImpl">
<property name="em" ref="entityManagerFactory" />
</bean>
<bean id="personService" class="com.journaldev.spring.service.PersonServiceImpl">
<property name="personDAO" ref="personDAO"></property>
</bean>
<context:component-scan base-package="com.journaldev.spring" />
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Usage:
import org.springframework.data.jpa.repository.JpaRepository;
import com.journaldev.spring.model.Person;
public interface PersonRepository extends JpaRepository<Person, Integer> {
}
Add to where to use:
@Autowired
private PersonRepository personRepository;
To add function to JpaRepository, we have 3 ways:
* Declare method name by combine keyword and fieldName
public
List<Person> findByLastName(String lastName);
* Using NamedQuery
@Entity
@NamedQuery
(name =
"Person.findByName"
, query =
"SELECT p FROM Person p WHERE LOWER(p.lastName) = LOWER(?1)"
)
@Table
(name =
"persons"
)
public
class
Person {
@Id
@GeneratedValue
(strategy = GenerationType.AUTO)
private
Long id;
Then add method which name match namedQuery name:
public
List<Person> findByName(String lastName);
* Using @Query at method definition
@Query
(
"SELECT p FROM Person p WHERE LOWER(p.lastName) = LOWER(:lastName)"
)
public
List<Person> find(
@Param
(
"lastName"
) String lastName);
Entity Manager
@PersistenceContext
private EntityManager em;
@Override
public List<Person> findByCountry(String country) {
List<Person> results = em.createNamedQuery("findByCountry").setParameter(1, country).getResultList();
return results;
}
EntityManager allow to run native Sql by em.createNativeQuery(String sqlString).
References:
http://www.petrikainulainen.net/spring-data-jpa-tutorial/
Subscribe to:
Posts (Atom)