By kswaughs | Monday, March 21, 2016

Spring Boot Batch Job Example

Spring Boot provides a lot of utility classes to perform batch jobs and schedule them at regular intervals. This helps developers focus on writing only business logic and hence saves our time and effort.

Spring Batch Framework offers two processing styles.

  • TaskletStep Oriented
  • Chunk Oriented

TaskletStep is used when either only reading or writing the data item is required.

Chunk is used when both reading and writing the data item is required.

In this example, I will explain how to configure batch jobs with Chunk Oriented Processing Model using spring boot.

Chunk Oriented Processing Model involves three components

1.ItemReader - An input operation, Used for providing the data. 
  It reads the data that will be processed.

2.ItemProcessor - A processing operation, Used for item transformation.
  It processes input object and transforms to output object.

3.ItemWriter - An Output operation, Used to write the data transformed by ItemProcessor.
  The data items can be written to database, memory or outputstream.

One item is read from an ItemReader, handed to an ItemProcessor, and transformed into an output object. Once the number of items read equals the commit interval, the entire chunk is written out via the ItemWriter, and then the transaction is committed.

In this sample application, we will read the input data from a csv file and transform into rest service request and call a back-end rest service with 3 data items at a time.

Batch Job involves Job Configuration and Step Configuration.

  • Step Configuration defines the reader, processor, writer and chunk items
  • Job Configuration defines the incrementer, listener and flow Step that we defined above.

Step 1 : Create a batch configuration class as below.

BatchConfiguration
package com.kswaughs.config;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import com.kswaughs.beans.Order;
import com.kswaughs.beans.SvcReq;
import com.kswaughs.order.OrderSvcInvoker;
import com.kswaughs.processor.JobCompletionNotificationListener;
import com.kswaughs.processor.OrderItemProcessor;

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;
    
    @Bean
    public Job processOrderJob() {
        return jobBuilderFactory.get("processOrderJob")
                .incrementer(new RunIdIncrementer())
                .listener(listener())
                .flow(orderStep())
                .end()
                .build();
    }
    
    @Bean
    public Step orderStep() {
        return stepBuilderFactory.get("orderStep")
                .<Order, SvcReq> chunk(3)
                .reader(reader())
                .processor(processor())
                .writer(writer())
                .build();
    }
    
    @Bean
    public FlatFileItemReader<Order> reader() {
        FlatFileItemReader<Order> reader = new FlatFileItemReader<Order>();
        reader.setResource(new ClassPathResource("PhoneData.csv"));
        reader.setLineMapper(new DefaultLineMapper<Order>() {{
            setLineTokenizer(new DelimitedLineTokenizer() {{
                setNames(new String[] { "orderID", "orderName" });
            }});
            setFieldSetMapper(new BeanWrapperFieldSetMapper<Order>() {{
                setTargetType(Order.class);
            }});
        }});
        return reader;
    }

    @Bean
    public OrderItemProcessor processor() {
        return new OrderItemProcessor();
    }
    
    @Bean
    public ItemWriter<SvcReq> writer() {
        return new OrderSvcInvoker();
    }

   @Bean
    public JobExecutionListener listener() {
        return new JobCompletionNotificationListener();
    }
    
}

Step 2: Below class is the processor that transforms into rest service request.

OrderItemProcessor
package com.kswaughs.processor;

import org.springframework.batch.item.ItemProcessor;

import com.kswaughs.beans.Order;
import com.kswaughs.beans.SvcReq;

public class OrderItemProcessor implements ItemProcessor<Order, SvcReq> {
    
    @Override
    public SvcReq process(final Order order) throws Exception {
      
        final SvcReq svcReq = new SvcReq();
        
        svcReq.setId(order.getOrderID());
        svcReq.setName(order.getOrderName().toUpperCase());

        System.out.println("Converting (" + order + ") into (" + svcReq + ")");

        return svcReq;
    }

}

Step 3: Below class is the Item Writer that calls the rest service.

OrderSvcInvoker
package com.kswaughs.order;

import java.util.List;

import org.springframework.batch.item.ItemWriter;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import com.kswaughs.beans.SvcReq;
import com.kswaughs.beans.SvcResp;

public class OrderSvcInvoker implements ItemWriter<SvcReq> {

    @Override
    public void write(List<? extends SvcReq> svcReqs) throws Exception {
        
        for (SvcReq svcReq : svcReqs) {
            
            RestTemplate restTemplate = new RestTemplate();
            
            ResponseEntity<SvcResp> respEntity = restTemplate
                .postForEntity("http://localhost:8080/phone/order", svcReq, SvcResp.class);
            
            SvcResp resp = respEntity.getBody();
            
            System.out.println("calling web service:" + resp);
        }
        
        System.out.println("Processed items:" + svcReqs.size());
    }

}

Step 4: Below class is the listener class that is executed when the job is finished.

JobCompletionNotificationListener
package com.kswaughs.processor;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;

public class JobCompletionNotificationListener extends JobExecutionListenerSupport {

    @Override
    public void afterJob(JobExecution jobExecution) {
        if(jobExecution.getStatus() == BatchStatus.COMPLETED) {
            System.out.println("BATCH JOB FINISHED SUCCESSFULLY");
        }
    }
}

Step 5: Below are the value bean classes for Item, rest request and rest response.

Order
package com.kswaughs.beans;

public class Order {
    
    private String orderID;
    private String orderName;

    public String getOrderID() {
        return orderID;
    }

    public void setOrderID(String orderID) {
        this.orderID = orderID;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Order [orderID=");
        builder.append(orderID);
        builder.append(", orderName=");
        builder.append(orderName);
        builder.append("]");
        return builder.toString();
    }

}

SvcReq
package com.kswaughs.beans;

public class SvcReq {
    
    private String id;
    
    private String name;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("SvcReq [id=");
        builder.append(id);
        builder.append(", name=");
        builder.append(name);
        builder.append("]");
        return builder.toString();
    }
}

SvcResp
package com.kswaughs.beans;

public class SvcResp {
    
    private String id;
    
    private String message;

    public String getId() {
        return id;
    }

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

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("SvcResp [id=");
        builder.append(id);
        builder.append(", message=");
        builder.append(message);
        builder.append("]");
        return builder.toString();
    }
}

Main class

BootApp
package com.kswaughs.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan({ "com.kswaughs" })
public class BootApp {
    
    public static void main(String[] args) {
        
        SpringApplication.run(new Object[] { BootApp.class }, args);

    }

}

Input csv file : PhoneData.csv

101,Apple IPhone
102,Samsung Galaxy Y
103,Moto E
104,Moto X
105,Yuphoria

Output:

2016-03-16 13:58:53.324  INFO 12876 --- [main] o.s.b.c.l.support.SimpleJobLauncher: Job: 
[FlowJob: [name=processOrderJob]] launched with the following parameters: [{run.id=1}]
2016-03-16 13:58:53.343  INFO 12876 --- [main] o.s.batch.core.job.SimpleStepHandler: Executing step: [orderStep]
Converting (Order [orderID=101, orderName=Apple IPhone]) into (SvcReq [id=101, name=APPLE IPHONE])
Converting (Order [orderID=102, orderName=Samsung Galaxy Y]) into (SvcReq [id=102, name=SAMSUNG GALAXY Y])
Converting (Order [orderID=103, orderName=Moto E]) into (SvcReq [id=103, name=MOTO E])
calling web service:SvcResp [id=101, message=APPLE IPHONE Processed successfully]
calling web service:SvcResp [id=102, message=SAMSUNG GALAXY Y Processed successfully]
calling web service:SvcResp [id=103, message=MOTO E Processed successfully]
Processed items:3
Converting (Order [orderID=104, orderName=Moto X]) into (SvcReq [id=104, name=MOTO X])
Converting (Order [orderID=105, orderName=Yuphoria]) into (SvcReq [id=105, name=YUPHORIA])
calling web service:SvcResp [id=104, message=MOTO X Processed successfully]
calling web service:SvcResp [id=105, message=YUPHORIA Processed successfully]
Processed items:2
BATCH JOB FINISHED SUCCESSFULLY
2016-03-16 13:58:53.786  INFO 12876 --- [main] o.s.b.c.l.support.SimpleJobLauncher: Job: 
[FlowJob: [name=processOrderJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED]

Maven POM

<dependencies>
    <!-- Spring framework related jars -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>1.3.0.RELEASE</version>
    </dependency>
    <!-- Batch related jars -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-batch</artifactId>
        <version>1.2.7.RELEASE</version>
    </dependency>
    <!-- Rest service call related jars -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
        <version>1.3.0.RELEASE</version>
        <exclusions>
              <exclusion>
                   <groupId>org.springframework.boot</groupId>
                   <artifactId>spring-boot-starter-web</artifactId>
               </exclusion>
           </exclusions> 
    </dependency>
</dependencies>

Recommend this on


By kswaughs | Thursday, February 25, 2016

Spring Boot task scheduler example

Spring Boot provides a simple and easy way to develop and run a Task scheduler without using any xml and bean configurations.

Simply add the annotation @Scheduled on the task scheduler method with required interval time.

In this example, we will see how to use Spring @Scheduled annotation to schedule a task.

Step 1 : pom.xml

pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>1.3.0.RELEASE</version>
</dependency>

Step 2 : Create Scheduler class

MyScheduledTasks
package com.kswaughs.tasks;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class MyScheduledTasks {

    private static final SimpleDateFormat dateFormat = 
        new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");

    @Scheduled(fixedRate = 10000)
    public void sendMailToCustomers() {

        System.out.println("sendMailToCustomers Job ran at " 
            + dateFormat.format(new Date()));

    }
}

Step 3 : Enable Scheduling

BootApp
package com.kswaughs.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
@ComponentScan({ "com.kswaughs.tasks" })
public class BootApp {
 
    public static void main(String[] args) {
  
        SpringApplication.run(new Object[] { BootApp.class }, args);

    }

}

Step 4 : Run the application

In this example, Job scheduler is configured to run at an interval of every 10 seconds.

  
sendMailToCustomers Job ran at 02/25/2016 14:30:02
sendMailToCustomers Job ran at 02/25/2016 14:30:12
sendMailToCustomers Job ran at 02/25/2016 14:30:22
sendMailToCustomers Job ran at 02/25/2016 14:30:32
sendMailToCustomers Job ran at 02/25/2016 14:30:42
sendMailToCustomers Job ran at 02/25/2016 14:30:52
sendMailToCustomers Job ran at 02/25/2016 14:31:02
sendMailToCustomers Job ran at 02/25/2016 14:31:12

Recommend this on


By kswaughs | Wednesday, February 24, 2016

Rest Service with Spring Boot

What is Spring Boot ?

  • Spring Boot simplifies the process of configuring and deploying the spring based applications.
  • Spring Boot is not a framework. It helps us to build, package and deploy Spring applications with minimal or no configurations.
  • Web applications or web services including RESTful services can be built as JAR file that can be run as stand-alone java application and no need to deploy in any external application server.

Spring Boot - Rest Service Example

In this below example, I will show you how to create a RESTful service with Spring Boot.

Step 1 : Use below maven dependency in your pom.xml. This jar will internally pulls all the required dependent jars in your classpath.

pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>1.3.0.RELEASE</version>
    </dependency>
</dependencies>

Step 2 : Create a main class which will initialize and runs the spring boot application.

BootApp
package com.kswaughs.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan({ "com.kswaughs.web" })
public class BootApp {
 
    public static void main(String[] args) {
  
        SpringApplication.run(new Object[] { BootApp.class }, args);

    }

}

Step 3 : Create Controller class to serve the rest service requests

UserController
package com.kswaughs.web.controller;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.kswaughs.web.beans.UserReq;
import com.kswaughs.web.beans.UserResp;

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
    public UserResp getUser(@PathVariable String id) {

        UserResp resp = new UserResp();
  
        resp.setId(id);
        resp.setStatus("SUCCESS");
        resp.setMessage("GET Method Processed successfully");

        return resp;
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public UserResp addUser(@RequestBody UserReq req) {

        UserResp resp = new UserResp();
  
        resp.setId(req.getId());
        resp.setStatus("SUCCESS");

        StringBuilder msg = new StringBuilder()
            .append("Hi ")
            .append(req.getName())
            .append(", POST method Processed successfully");
  
        resp.setMessage(msg.toString());
  
        return resp;
    }

}

Step 4 : Create below model objects to convert JSON requests and responses into java objects.

Request Object - UserReq
package com.kswaughs.web.beans;

public class UserReq {
 
    private String id;
 
    private String name;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("UserReq [id=");
        builder.append(id);
        builder.append(", name=");
        builder.append(name);
        builder.append("]");
        return builder.toString();
    }
}

Response Object - UserResp
package com.kswaughs.web.beans;

public class UserResp {
 
    private String status;
 
    private String id;
 
    private String message;

    public String getStatus() {
         return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getId() {
        return id;
    }

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

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("UserResp [status=");
        builder.append(status);
        builder.append(", id=");
        builder.append(id);
        builder.append(", message=");
        builder.append(message);
        builder.append("]");
        return builder.toString();
    }
}

Step 5 : Start the application. You can start this application as a normal stand-alone java application and I am explaining below different ways of running this application.

  1. Run from Eclipse
  2. Run from Maven command
  3. Run from jar

1. Run from Eclipse

From Eclipse IDE, Go to BootApp.java class and Run as Java application.

2. Run from Maven command

Add below artifact as your parent pom in your pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.0.RELEASE</version>
</parent>

Run with maven command mvn spring-boot:run.

3. Run from jar

Add below maven build plugin

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Run maven command mvn package and it generates jar file with project_name in target directory.

Run the command java -jar target/project_name-1.0.jar from command line.

Step 6: Test the application

  
 Test 1 : 
 operation : get
 method : GET
 URL : http://localhost:8080/user/get/12345
 Response :
 
 {
    "status": "SUCCESS",
    "id": "12345",
    "message": "GET Method Processed successfully"
 }
 Test 2 :
 operation : add
 method : POST
 URL : http://localhost:8080/user/add
 Request
 { "id" : "2222", "name" : "kswaughs" }

 Response
 {
    "status": "SUCCESS",
    "id": "2222",
    "message": "Hi kswaughs, POST method Processed successfully"
 }

Recommend this on


By kswaughs | Friday, February 12, 2016

Spring AOP with annotations

Spring AOP allows us to add multiple aspects without changing the actual business logic code of java files like controllers, service etc.

In this example, I am going to explain you how to apply aspects in a spring based application using annotations.

I am adding these examples on top of the existing spring application that is explained in below articles.

Step 1: Add @EnableAspectJAutoProxy annotation to the spring configuration file.

SpringWebConfig
package com.kswaughs.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import com.kswaughs.interceptor.TransactionInterceptor;

@EnableAspectJAutoProxy
@EnableWebMvc 
@Configuration
@ComponentScan({ "com.kswaughs.web" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }
 
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/jsps/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
  
        registry.addInterceptor(new TransactionInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/phones");
    }
}

Step 2: Create an Aspect class and define the pointcut expression where you want to apply this aspect. In this example, I am applying this aspect after PhoneService.getPhoneDetails() method is executed.

PhoneLogAspect
package com.kswaughs.web.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class PhoneLogAspect {

    @AfterReturning(
        pointcut = "execution(* com.kswaughs.web.service.PhoneService.getPhoneDetails(..))",
        returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {

        System.out.println("******");
        System.out.println("logAfterReturning() is running!");
        System.out.println("Method Intercepted : " + joinPoint.getSignature().getName());
        System.out.println("Method returned value is : " + result);
        System.out.println("******");
    }
}

Below is the output printed in console when phone details page is rendered to the browser.

output:
******
logAfterReturning() is running!
Method Intercepted : getPhoneDetails
Method returned value is : Phone [id=2, name=Nokia Lumia, price=12,000]
******

Maven dependencies

pom.xml
<dependencies>
    <!-- Spring framework -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.11</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.7.2</version>
    </dependency>
    <!-- JSTL for jsp pages -->
        <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <!-- Servlet API jars -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

Recommend this on


By kswaughs | Tuesday, February 9, 2016

Spring mvc interceptor with annonations

Interceptors are used to intercept the web requests from the user and they are executed before and after processing the requests.

Spring MVC allows us to intercept through handler interceptors. The custom interceptor have to extend the HandlerInterceptorAdapter class, and override below methods :

1. preHandle() is called before the handler execution and returns a boolean value. If it is true then continue the handler execution chain otherwise stop the execution chain and return it.

2. postHandle() is called after the handler execution, allow manipulate the ModelAndView object before render it to JSP page.

In this example, I am printing the request URI before processing the request and printing the modelMap of ModelAndView object after processing the request.

Step 1 : Create an interceptor class that extends HandlerInterceptorAdapter.

TransactionInterceptor
package com.kswaughs.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class TransactionInterceptor extends HandlerInterceptorAdapter {
  
    @Override
    public boolean preHandle(
        HttpServletRequest request,
        HttpServletResponse response, 
        Object handler) throws Exception {
  
        System.out.println("Before Request Processing : request.getRequestURI(): "
            + request.getRequestURI());
  
        return true;
    }
 
    @Override
    public void postHandle(
        HttpServletRequest request,
        HttpServletResponse response, Object handler,
        ModelAndView modelAndView) throws Exception {

        System.out.println("After Request Processing : modelAndView.getModelMap(): "
            + modelAndView.getModelMap());
    }
}

Step 2 : Map the interceptors to the required urls.

My appname is spring_app and I have two URIs
/phones
/phones/details
But I applied interceptor to only '/phones/details'. 
SpringWebConfig

package com.kswaughs.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import com.kswaughs.interceptor.TransactionInterceptor;

@EnableWebMvc 
@Configuration
@ComponentScan({ "com.kswaughs.web" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }
 
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/jsps/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
  
        registry.addInterceptor(new TransactionInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/phones");
    }
}

Output in server console

Before Request Processing : request.getRequestURI(): /spring_app/phones/details
After Request Processing : modelAndView.getModelMap(){phone=Phone [id=2, name=Nokia Lumia, price=12,000], org.springframework.validation.BindingResult.phone=org.springframework.validation.BeanPropertyBindingResult: 0 errors}

Recommend this on


By kswaughs | Thursday, February 4, 2016

Spring MVC Web application with annotations and maven

Step 1 : Create a Configuration class that extends WebMvcConfigurerAdapter which is equivalent to spring dispatcher context xml.

SpringWebConfig
package com.kswaughs.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc 
@Configuration
@ComponentScan({ "com.kswaughs.web" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }
 
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/jsps/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}


Step 2 : Create a Spring Web Initializer class that extends AbstractAnnotationConfigDispatcherServletInitializer which is equivalent to web.xml.

SpringWebInitializer
package com.kswaughs.servlet;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.kswaughs.config.SpringWebConfig;

public class SpringWebInitializer extends
    AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[] { SpringWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[] {};
    }
}

Step 3 : Create below model object to pass the data between spring controller and JSPs.

Model Object - Phone
package com.kswaughs.web.beans;

public class Phone {
 
    private String id;
 
    private String name;
 
    private String price;
 
    public Phone() { }
 
    public Phone(String id, String name) {
        this.id = id;
        this.name = name;
    }
 
    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

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

    public void setName(String name) {
        this.name = name;
    }
}

Step 4 : Create Controller class to serve the web requests

PhoneController
package com.kswaughs.web.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.kswaughs.web.beans.Phone;
import com.kswaughs.web.service.PhoneService;

@Controller
@RequestMapping(value = "/phones")
public class PhoneController {
 
    @Autowired
    PhoneService phoneSvc;
 
    @RequestMapping(value = "", method = RequestMethod.GET)
    public ModelAndView index(@ModelAttribute("phone") Phone phone) {
  
        List phonesList = phoneSvc.getPhoneslist();
   
        return new ModelAndView("index", "phones",  phonesList);
    }
 
    @RequestMapping(value = "/details", method = RequestMethod.POST)
    public ModelAndView showPrice(@ModelAttribute("phone") Phone phone ) {
    
        phone = phoneSvc.getPhoneDetails(phone);
    
        return new ModelAndView("details", "phone", phone);
    }
}

Step 5 : Create Service class to process the business logic

PhoneService
package com.kswaughs.web.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.kswaughs.web.beans.Phone;

@Service
public class PhoneService {
 
    public List getPhoneslist() {
  
        List phonesList = new ArrayList();
  
        phonesList.add(buildPhone("1", "Samsung Galaxy Y"));
        phonesList.add(buildPhone("2", "Nokia Lumia"));
        phonesList.add(buildPhone("3", "Moto G"));
  
        return phonesList;
    }
 
    public Phone getPhoneDetails(Phone phone) {
    
        final String id = phone.getId();
        String price = null;
        if("1".equals(id)) {
            phone = buildPhone("1", "Samsung Galaxy Y");
            price = "10,000";
   
        } else if("2".equals(id)) {
            phone = buildPhone("2", "Nokia Lumia");
            price = "12,000";
  
        } else if("3".equals(id)) {
            phone = buildPhone("3", "Moto G");
            price = "14,000";
        }
  
        phone.setPrice(price);
        return phone;
     }
 
    private Phone buildPhone(String id, String name) {
  
        Phone phone = new Phone(id, name);
        return phone;
    }
}

Step 6 : Welcome page to show list of available phones

index.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<spring:url value="/resources/css/style.css" var="style" />
<link href="${style}" rel="stylesheet" />
</head>
<body>
<div>
<p>Welcome to Phones Store</p>
<p>Choose your Phone below</p>
<div>
<form:form method="post" action="${pageContext.request.contextPath}/phones/details" 
modelAttribute="phone">
<c:forEach var="ph" items="${phones}">
<div><form:radiobutton path="id" value="${ph.id}"/>${ph.name}</div>
</c:forEach>
<input type="submit"  value="submit"/>
</form:form>
</div>
</div>
</body>
</html>

Step 7 : Phone details page to display user selected phone name and price.

details.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<spring:url value="/resources/css/style.css" var="style" />
<link href="${style}" rel="stylesheet" />
</head>
<body>
<div>
<p>Welcome to Phones Store</p>
<p>Your phone details</p>
<div>Phone : ${phone.name}</div>
<div>Price : ${phone.price} Rs/<sub>-</sub></div>
</div>
</body>
</html>

Step 8 : Testing the application. Run the maven build and generated the war with name 'spring_app' and deployed in Tomcat 7 server.

Welcome page

http://localhost:8080/spring_app/phones

Welcome to Phones Store
Choose your Phone below
Samsung Galaxy Y
Nokia Lumia
Moto G

Details page

http://localhost:8080/spring_app/phones/details

Welcome to Phones Store
Your phone details
Phone : Moto G
Price : 14,000 Rs/-

Use Below maven dependencies in your pom.xml.

pom.xml
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
</dependency>
<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>
    <scope>provided</scope>
</dependency>

Recommend this on


By kswaughs | Thursday, December 24, 2015

Spring restful service without web.xml

Spring 3 WebMVC provides a lot of features and makes Spring developers easier to develop several applications like Web applications and REST services. Spring 3.2.10.RELEASE version has more advanced features with Spring annotations where developers need not to define web.xml or any other kind of context xmls.

In this below example, I will show you how to use Spring 3 MVC annotations to develop a RESTful service.

Step 1 : Create a Configuration class that extends WebMvcConfigurerAdapter which is equivalent to spring dispatcher application context xml.

SpringWebConfig
package com.kswaughs.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@EnableWebMvc 
@Configuration
@ComponentScan({ "com.kswaughs.web" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
   
}

Step 2 : Create a Spring Web Initializer class that extends AbstractAnnotationConfigDispatcherServletInitializer which is equivalent to web.xml.

SpringWebInitializer
package com.kswaughs.servlet;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.kswaughs.config.SpringWebConfig;

public class SpringWebInitializer extends
    AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[] { SpringWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[] {};
    }

}

Step 3 : Create Controller class to serve the rest service requests

UserController
package com.kswaughs.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.kswaughs.web.beans.UserReq;
import com.kswaughs.web.beans.UserResp;

@Controller
@RequestMapping("usersvc")
public class UserController {

    @RequestMapping(value = "get/{id}", method = RequestMethod.GET)
    @ResponseBody
    public UserResp getUser(@PathVariable String id) {

        UserResp resp = new UserResp();
  
        resp.setId(id);
        resp.setStatus("SUCCESS");
        resp.setMessage("GET Method Processed successfully");

        return resp;
    }

    @RequestMapping(value = "add", method = RequestMethod.POST)
    @ResponseBody
    public UserResp addUser(@RequestBody UserReq req) {

        UserResp resp = new UserResp();
  
        resp.setId(req.getId());
        resp.setStatus("SUCCESS");

        StringBuilder msg = new StringBuilder()
            .append("Hi ").append(req.getName())
            .append(", POST method Processed successfully");
  
        resp.setMessage(msg.toString());

        return resp;
    }
}

Step 4 : Create below model objects to convert JSON requests and responses into java objects.

Request Object - UserReq
package com.kswaughs.web.beans;

public class UserReq {
 
    private String id;
 
    private String name;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("UserReq [id=");
        builder.append(id);
        builder.append(", name=");
        builder.append(name);
        builder.append("]");
        return builder.toString();
    }
}

Response Object - UserResp
package com.kswaughs.web.beans;

public class UserResp {
 
    private String status;
 
    private String id;
 
    private String message;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getId() {
        return id;
    }

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

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("UserResp [status=");
        builder.append(status);
        builder.append(", id=");
        builder.append(id);
        builder.append(", message=");
        builder.append(message);
        builder.append("]");
        return builder.toString();
    }
}

Step 5 : Testing the service. Run the maven build and generated the war with name 'spring-rest-1.0' and deployed in Tomcat 7 server.

  
Test 1
operation : get
method : GET
URL : http://localhost:8080/spring_rest-1.0/usersvc/get/12345
Response >>
{
    "message": "GET Method Processed successfully",
    "id": "12345",
    "status": "SUCCESS"
}
Test 2
operation : add
method : POST
URL : http://localhost:8080/spring_rest-1.0/usersvc/add
Request >>
{     
    "id" : "2222", 
    "name" : "kswaughs"    
}

Response >>
{
    "status": "SUCCESS",
    "id": "2222",
    "message": "Hi kswaughs, POST method Processed successfully"
}

Use Below maven dependencies in your pom.xml. In maven war plugin, set failOnMissingWebXml to false, Otherwise maven war plugin will fail to generate WAR when web.xml is not used.

pom.xml
<properties>
    <spring.version>3.2.10.RELEASE</spring.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
</dependencies>
<build>
    <defaultGoal>install</defaultGoal>
    <plugins>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <failOnMissingWebXml>false</failOnMissingWebXml>
                <archive>
                    <manifestEntries>
                        <Build-Jdk>1.6</Build-Jdk>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

Recommend this on


By kswaughs | Monday, November 9, 2015

Spring Web MVC Custom Validator

This post describes how to use Spring Custom Validator to perform the input form validations with examples.

Create a model object to hold the input form values.

Data Model class to hold user name
public class UserBean {

 private String userName;

 public String getUserName() {
  return userName;
 }

 public void setUserName(String userName) {
  this.userName = userName;
 }
}

Create a custom validator class and use ValidationUtils with custom error messages.

Validator class
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

@Component
public class UserValidator implements Validator{

 @Override
 public boolean supports(Class paramClass) {

  return UserBean.class.equals(paramClass);
 }

 @Override
 public void validate(Object arg0, Errors errors) {
  ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", 
       "error.userName" , "Invalid user name");
 }
}

In controller, Call this validate method and handle as below.

Controller method
@RequestMapping(value = "/user", method = RequestMethod.POST)
public String processUser(@ModelAttribute UserBean userBean, BindingResult result) {

    UserValidator.validate(userBean, result);

    if( ! result.hasErrors()) {
       return "success";
    }

    return "input";
}

In your input.jsp page, add this below element where you want to show the message

<form:errors path="userName" cssStyle="color: #ff0000;"/>

Recommend this on