Saturday, December 19, 2015

Spring MVC Implements RESTful

Implements following requirement:

  1. Using maven to manage project 
  2. Spring mvc as main architecture
  3. Annotation configuration
  4. Using JSON request response and java object auto converting

1. Dependencies and pom

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <slf4j.version>1.7.12</slf4j.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-framework-bom</artifactId>
                <version>4.1.7.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- javaee -->
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>
     
        <!-- springframework core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
        </dependency>
     
        <!-- springframework web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
     
        <!-- json bind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.6.4</version>
        </dependency>
     
        <!-- Log -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>${slf4j.version}</version>
        </dependency>  
    </dependencies>

2. web.xml

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/webContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>

3. webContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans     
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.gemalto.offerflex" />
    <mvc:annotation-driven />
    <context:annotation-config/>
    
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
    <!-- Configure to plugin JSON as request and response in method handler -->
    <bean  class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="jsonMessageConverter"/>
            </list>
        </property>
    </bean>
    
    <bean id="jsonMessageConverter"
               class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</beans>

4. VO

JSON format message in request body will be parsed to VO.
VO will be convert to JSON message and written into response body.

public class House {
    private String address;
    private int roomNum;

    public String getAddress() {
        return address;
    }

    public int getRoomNum() {
        return roomNum;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void setRoomNum(int roomNum) {
        this.roomNum = roomNum;
    }
}


public class Person {
    
    private String id;
    private String name;
    private List<House> houses;
    
    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
    
    public List<House> getHouses(){
        return houses;
    }

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

    public void setName(String name) {
        this.name = name;
    }
    
    public void setHouses(List<House> houses){
        this.houses = houses;
    }
     
}

5. Controller

@RestController
@RequestMapping ("/rest")
public class TestRestController {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(TestRestController.class);
    
    /**
     * http://localhost:7001/WebTest/rest/params.action?id=10&name=wang bo
     */
    @RequestMapping(value="/params", method=RequestMethod.GET)
    @ResponseStatus(value=HttpStatus.OK)
    public String params(@RequestParam String id, @RequestParam String name){
        
        LOGGER.info("params...");
        LOGGER.info("id  : " + id);
        LOGGER.info("name: " + name);
        
        return "Received!";
    }
    
    /**
     * http://localhost:7001/WebTest/rest/pathVariable/10/Tom.action
     */
    @RequestMapping(value="/pathVariable/{id}/{name}", method=RequestMethod.GET)
    @ResponseStatus(value=HttpStatus.OK)
    public String pathVariable(@PathVariable String id, @PathVariable String name){
        
        LOGGER.info("pathVariable...");
        LOGGER.info("id  : " + id);
        LOGGER.info("name: " + name);
        
        return "Received!";
    }
    
    /**
     * Json object, Person, does not implements Serializable interface and does not need any constructor.
     * 
     */
    @RequestMapping(value="/jsonObj", method=RequestMethod.POST)
    @ResponseStatus(value=HttpStatus.OK)
    public Person jsonObj(@RequestBody Person person){
        return dealWith(person);
    }
    
    private Person dealWith(Person person){
        LOGGER.info("jsonObj...");
        LOGGER.info("id  : " + person.getId());
        LOGGER.info("name: " + person.getName());
        
        if(person.getHouses() != null){
            for(House house : person.getHouses()){
                LOGGER.info("houses --- " + house.getAddress() + ", " + house.getRoomNum());
            }
        }else{
            LOGGER.info("houses --- null");
        }
        
        return person;
    }
    
}

6. Difference between @RestController and @Controller

They have no difference essentially. @RestController equals to @Controller plus @ResponseBody.