Spring REST

Spring REST

示例实现

1. 请求REST接口返回类转换的JSON或XML数据

2. POST JSON数据到REST接口自动转为类数据

服务端

Bean

package com.qunar.bean;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * Created with IntelliJ IDEA.
 * User: zhenwei.liu
 * Date: 13-7-26
 * Time: 下午6:53
 * To change this template use File | Settings | File Templates.
 */
@XmlRootElement // 标注类名为XML根节点
@XmlAccessorType(XmlAccessType.FIELD)   // 表示将所有域作为XML节点
public class User {
    private long id;
    private String username;
    private String password;

    public long getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

Controller

package com.qunar.controller;

import com.qunar.bean.User;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

/**
 * Created with IntelliJ IDEA.
 * User: zhenwei.liu
 * Date: 13-7-26
 * Time: 下午6:54
 * To change this template use File | Settings | File Templates.
 */
@Controller
@RequestMapping("/users")
public class UserController {
    // headers属性标明该方法只接受该Accept头的请求
    @RequestMapping(value = "/{id}",
            method = RequestMethod.GET)
//            headers = {"Accept=text/xml, application/json, application/xml"})
    // @ResponseBody 表示返回的对象将转换为客户端Accept头要求的表达形式
    // 假如客户端请求头没包含任何形式,则假设客户端可接受任何形式的返回
    // 返回的类型匹配方法默认值是先查看URL扩展名,没有扩展名则匹配Accept头,否则匹配defaultContentType
    // @PathVariable 表示参数值来自URL,如果参数名与URL括号内形参相同
    // 可以省略PathVariable内的参数名
    public
    @ResponseBody
    User getUser(@PathVariable("id") long id) {
        User user = new User();
        user.setUsername("root");
        user.setPassword("root123");
        user.setId(id);
        return user;
    }

    // 设置RequestMapping的headers参数标明请求体的内容是json数据
    @RequestMapping(value = "/add", method = RequestMethod.POST,
            headers = "Content-Type=application/json")
    // @ResponseStatus表示响应状态 NO_CONTENT表示无响应内容
    @ResponseStatus(HttpStatus.NO_CONTENT)
    // 没有配置ViewResolver的情况下@ResponseBody不能省略,否则404
    // @RequestBody表示将请求体的数据转为user类
    public @ResponseBody void addUser(@RequestBody User user) {
        System.out.println(user.getId() + "|" + user.getUsername());
    }
}

dispatcher-servlet.xml

<?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: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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 自动注册bean -->
    <context:component-scan base-package="com.qunar">
        <context:include-filter type="regex" expression=".controller.*"/>
    </context:component-scan>
    <!-- 依赖注入注释功能 -->
    <context:annotation-config/>
    <!-- 开启MVC注释功能 -->
    <mvc:annotation-driven/>

    <!-- 转换器配置:只有配置好了转换器才能进行类与JSON和XML的转换 -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <!-- String 转换器 -->
                <ref bean="stringHttpMessageConverter"/>
                <!-- JSON 转换器 -->
                <ref bean="jsonHttpMessageConverter"/>
                <!-- XML 转换器 -->
                <ref bean="marshallingHttpMessageConverter"/>
            </list>
        </property>
    </bean>


    <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/>

    <bean id="jsonHttpMessageConverter"
          class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>

    <bean id="marshallingHttpMessageConverter"
          class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
        <constructor-arg ref="jaxbMarshaller"/>
        <property name="supportedMediaTypes" value="application/xml" />
    </bean>


    <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <!-- XML转换器需要绑定需要转换的类 -->
        <property name="classesToBeBound">
            <list>
                <value>com.qunar.bean.User</value>
            </list>
        </property>
    </bean>


</beans>

applicationContext.xml

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.qunar">
        <context:include-filter type="regex" expression=".bean.*"/>
    </context:component-scan>


</beans>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
           version="2.5">

    <!-- 定义根目录 -->
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>restServer.root</param-value>
    </context-param>
    <listener>
        <listener-class>
            org.springframework.web.util.WebAppRootListener
        </listener-class>
    </listener>

    <!-- 定义配置文件路径 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath*:spring/context/applicationContext.xml
        </param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 清理残留在ServletContext的弃用参数的Listener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextCleanupListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:spring/context/dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

另外很重要的是把依赖包配好,否则各种ClassNotDefined

        <!-- JSON 转换器 -->
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.12</version>
        </dependency>

        <!-- XML 转换器 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>3.1.4.RELEASE</version>
        </dependency>

客户端

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

/**
 * Created with IntelliJ IDEA.
 * User: zhenwei.liu
 * Date: 13-7-26
 * Time: 下午10:41
 * To change this template use File | Settings | File Templates.
 */
public class Test {
    public static String urlGet = "http://localhost:8080/users/{id}";
    public static String urlPost = "http://localhost:8080/users/add";
    public static RestTemplate rt = new RestTemplate();

    // 从Rest接口获取数据
    public static void getUser(long userId) {
        HttpHeaders headers = new HttpHeaders();
        // 设置Accept表示浏览器支持的MIME类型,此处意思是要返回的类型
        headers.setAccept(MediaType.parseMediaTypes(MediaType.APPLICATION_XML_VALUE));
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(headers);

        System.out.println(
                rt.exchange(
                        urlGet,
                        HttpMethod.GET,
                        requestEntity,
                        String.class,
                        userId
                )
        );
        System.out.println(
                rt.getForObject(urlGet, String.class, userId)
        );
    }

    // 传JSON数据到REST接口,自动将JSON数据转化成类
    public static void addUserByJson(String userJson) {
        HttpHeaders headers = new HttpHeaders();
        // 设置ContentType标明数据是JSON数据,否则报415(Unsupported Media Type)
        // 此处必须和REST接口的RequestMapping的ContentType对应
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(userJson, headers);
//        System.out.println(requestEntity.getBody().toString());
        rt.exchange(urlPost, HttpMethod.POST, requestEntity, null);
    }

    public static void main(String[] args) {
        getUser(1);
        addUserByJson("{"id":1,"username":"root","password":"root123"}");
    }
}

输出数据

<200 OK,<?xml version="1.0" encoding="UTF-8" standalone="yes"?><user><id>1</id><username>root</username><password>root123</password></user>,{Server=[Apache-Coyote/1.1], Content-Type=[application/xml], Transfer-Encoding=[chunked], Date=[Sat, 27 Jul 2013 16:02:04 GMT]}>


{"id":1,"username":"root","password":"root123"}