Restful 介绍及SpringMVC+restful 实例讲解

 

 

restful不是一个框架,称为一种编码更烦更贴切吧,其核心类位于spring-web.jar中,即RestTemplate.class

restful是rpc通过http协议的一种实现方式,和webservice一样,请参阅我的其他文章

 

今天我将在springmvc环境中进行演示,首先请看我其他博客文章下载整理好的源码,整理好的源码可以直接用于商业项目开发

整理好的代码项目结构如下:

本次讲的restful大致如下

 

文采不好,开始贴代码:

① 常量工具类,用于保存http、:、?、=、&这些的

package xiaochangwei.zicp.net.restful.tools;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class CommonUtils
{
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);

    private static ObjectMapper objectMapper = new ObjectMapper();

    public static String HTTP_SLASH = "/";

    public static String HTTP_COLON = ":";

    public static String HTTP_QUESTION_MARK = "?";

    public static String HTTP_EQUAL_MARK = "=";
    
    public static String HTTP_AMPERSAND = "&";
    
    public static int INIT_VALUE = -1;

    public static String changeObjectToJsonStr(Object object) throws JsonProcessingException
    {
        String content = objectMapper.writeValueAsString(object);

        logger.debug("content = [{}].", content);
        return content;
    }

    public static <T> T changeJsonStrToObject(String content, Class<T> valueType)
            throws JsonParseException, JsonMappingException, IOException
    {
        return objectMapper.readValue(content, valueType);
    }
}

② 模块枚举定义类

package xiaochangwei.zicp.net.restful.tools;

public enum ModuleEnum {
    MODULE_SERVICE("services", 1), 
    MODULE_ACCESS("icp/url", 2), 
    MODULE_SMSSend("sms/Api/Send.do", 3),
    MODULE_TEST("project-web/restful/restfulService", 4),;

    private String name;

    private int index;

    private ModuleEnum(String name, int index) {
        this.name = name;
        this.index = index;
    }

    public static String getName(int index) {
        for (ModuleEnum m : ModuleEnum.values()) {
            if (m.getIndex() == index) {
                return m.name;
            }
        }
        return null;
    }

    public String getName() {
        return name;
    }

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

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

③ 参数封装类

package xiaochangwei.zicp.net.restful.tools;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpMethod;

public class ParamEntity
{
    // IP地址。
    private String ipaddr;
    
    // IP端口。
    private String port;

 ④ 核心调用类

package xiaochangwei.zicp.net.restful.tools;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

@SuppressWarnings("deprecation")
public class HttpClientUtils
{
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
    
    private static String HTTP_PROTOCOL = "http://";
    
    public static ResponseEntity<String> Execute(ParamEntity paramEntity)
    {
        HttpClient httpClient  = null;
        
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());  
            trustStore.load(null, null);  
  
            SSLSocketFactory sf = new MySSLSocketFactory(trustStore);  
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  
  
            SchemeRegistry registry = new SchemeRegistry();  
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), Integer.valueOf(paramEntity.getPort())));  
            registry.register(new Scheme("https", sf, Integer.valueOf(paramEntity.getPort())));  
  
            ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);  
            httpClient =  new DefaultHttpClient(ccm);
        } catch (Exception e) {
            logger.info("httpclient创建错误.");
        }
        
        HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        httpComponentsClientHttpRequestFactory.setConnectTimeout(120*1000);
        httpComponentsClientHttpRequestFactory.setReadTimeout(120*1000);
        RestTemplate rt = new RestTemplate(httpComponentsClientHttpRequestFactory);

        String url = HttpClientUtils.generateUrl(paramEntity);
        
        HttpEntity<String> requestEntity = HttpClientUtils.generateHttpEntity(paramEntity);
        
        try
        {
            System.out.println("httpMethod = " + paramEntity.getHttpMethod());
            System.out.println("url = " + url);
            System.out.println("requestEntity = " + requestEntity);
            
            ResponseEntity<String> responseEntity =
                    rt.exchange(url, paramEntity.getHttpMethod(), requestEntity, String.class);
            
            logger.debug("responseEntity = [{}].", responseEntity);
            System.out.println("responseEntity = " + responseEntity);
            return responseEntity;
        }
        catch (Exception e)
        {
            System.out.println("info: " + e.getMessage());
            logger.debug("error info:  = [{}].", e.getMessage());
            return generateRespWhenException(e);
        }
    }
    
    private static ResponseEntity<String> generateRespWhenException(Exception e)
    {
        String msg = e.getMessage();
        String[] strs = msg.split(" ");
        HttpStatus retCode;
        try
        {
            retCode = HttpStatus.valueOf(Integer.valueOf(strs[0]));
        }
        catch (NumberFormatException ex)
        {
            retCode = HttpStatus.SERVICE_UNAVAILABLE;
        }
        
        return new ResponseEntity<String>(retCode);
    }
    
    private static String generateUrl(ParamEntity paramEntity)
    {
        StringBuilder url = new StringBuilder();
        
        url.append(HTTP_PROTOCOL)
            .append(paramEntity.getIpaddr())
            .append(CommonUtils.HTTP_COLON)
            .append(paramEntity.getPort())
            .append(CommonUtils.HTTP_SLASH);
        
        if (!StringUtils.isEmpty(paramEntity.getVersion()))
        {
            url.append(paramEntity.getVersion()).append(CommonUtils.HTTP_SLASH);
        }
        
        ModuleEnum module = paramEntity.getModule();
        switch (module)
        {
            case MODULE_SERVICE:
                addServiceUri(url);
                break;             
            case MODULE_SMSSend:
                addSMSSendUri(url, paramEntity);
                break;
            case MODULE_TEST:
                addUserUri(url, paramEntity);
                break;
            default:
                logger.error("module [{}] does not exist.", module.getName());
                break;
        }
        
        logger.debug("url = [{}].", url.toString());
        return url.toString();
    }
    
    private static HttpEntity<String> generateHttpEntity(ParamEntity frontInfo)
    {
        String data = frontInfo.getData();
        
        HttpHeaders headers = new HttpHeaders();
        for (String headerKey : frontInfo.getHeadersMap().keySet())
        {
            String headerValue = frontInfo.getHeadersMap().get(headerKey);
            if (!StringUtils.isEmpty(headerValue))
            {
                headers.add(headerKey, headerValue);
            }
        }
        
        HttpEntity<String> requestEntity = new HttpEntity<String>(data, headers);
        
        logger.debug("requestEntity = [{}].", requestEntity);
        return requestEntity;
    }
    
    private static void addServiceUri(StringBuilder url)
    {
        url.append(ModuleEnum.MODULE_SERVICE.getName());
    }
    
    private static void addUserUri(StringBuilder url, ParamEntity frontInfo)
    {
        url.append(ModuleEnum.MODULE_TEST.getName());
        
        if (!StringUtils.isEmpty(frontInfo.getUser_id()))
        {
            url.append(CommonUtils.HTTP_SLASH).append(frontInfo.getUser_id());
        }
    }
    
    private static void addSMSSendUri(StringBuilder url, ParamEntity frontInfo)
    {
        url.append(ModuleEnum.MODULE_SMSSend.getName());

        boolean hasParam = false;
        hasParam = addParamsToUri(hasParam, "SpCode", frontInfo.getSmsSpCode(), url);
        hasParam = addParamsToUri(hasParam, "LoginName", frontInfo.getSmsLoginName(), url);
        hasParam = addParamsToUri(hasParam, "Password", frontInfo.getSmsPassword(), url);
        hasParam = addParamsToUri(hasParam, "MessageContent", frontInfo.getSmsMessageContent(), url);
        hasParam = addParamsToUri(hasParam, "UserNumber", frontInfo.getSmsUserNumber(), url);
        hasParam = addParamsToUri(hasParam, "SerialNumber", frontInfo.getSmsSerialNumber(), url);
        hasParam = addParamsToUri(hasParam, "ScheduleTime", frontInfo.getSmsScheduleTime(), url);
        hasParam = addParamsToUri(hasParam, "f", frontInfo.getSmsf(), url);
    }
    
    private static boolean addParamsToUri(boolean hasParam, String descripition, String param, StringBuilder url)
    {
        if (!StringUtils.isEmpty(param) && !param.equals("null"))
        {
            if (hasParam)
            {
                url.append(CommonUtils.HTTP_AMPERSAND);
            }
            else
            {
                url.append(CommonUtils.HTTP_QUESTION_MARK);
            }
            url.append(descripition).append(CommonUtils.HTTP_EQUAL_MARK).append(param);
            
            return true;
        }
        
        return false;
    }
    
    private static class MySSLSocketFactory extends SSLSocketFactory {  
        
        SSLContext sslContext = SSLContext.getInstance("TLS");  
  
        public MySSLSocketFactory(KeyStore truststore)  
                throws NoSuchAlgorithmException, KeyManagementException,  
                KeyStoreException, UnrecoverableKeyException {  
                super(truststore);  
  
            TrustManager tm = new X509TrustManager() {  
                public void checkClientTrusted(X509Certificate[] chain, String authType)  
                        throws CertificateException {  
                }  
  
                public void checkServerTrusted(X509Certificate[] chain, String authType)  
                        throws CertificateException {  
                }  
  
                public X509Certificate[] getAcceptedIssuers() {  
                    return null;  
                }  
            };  
  
            sslContext.init(null, new TrustManager[] { tm }, null);  
        }  
  
        @Override  
        public Socket createSocket(Socket socket, String host, int port, boolean autoClose)  
                throws IOException, UnknownHostException {  
            return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);  
        }  
  
        @Override  
        public Socket createSocket() throws IOException {  
            return sslContext.getSocketFactory().createSocket();  
        }  
    }  
}

⑤ 调用入口

package xiaochangwei.zicp.net.restful.operation.impl;

import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import xiaochangwei.zicp.net.restful.operation.RestfulTestOperation;
import xiaochangwei.zicp.net.restful.tools.ParamEntity;
import xiaochangwei.zicp.net.restful.tools.HttpClientUtils;
import xiaochangwei.zicp.net.restful.tools.ModuleEnum;

/**
 * @author http://www.cnblogs.com/xiaochangwei
 * @date 2016年4月20日
 * 
 */
@Component
public class RestfulTestOperationImpl implements RestfulTestOperation {

    public ResponseEntity<String> restfulTestMethod(ParamEntity paramEntity) {
        paramEntity.setModule(ModuleEnum.MODULE_TEST);

        paramEntity.setHttpMethod(HttpMethod.POST);

        ResponseEntity<String> responseEntity = HttpClientUtils.Execute(paramEntity);

        return responseEntity;
    }
}

 

⑥ service层参数封装、调用、返回结果处理类

package xiaochangwei.zicp.net.service.restful;

import java.util.HashMap;
import java.util.Map;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import xiaochangwei.zicp.net.restful.operation.RestfulTestOperation;
import xiaochangwei.zicp.net.restful.tools.ParamEntity;

/**
 * @author http://www.cnblogs.com/xiaochangwei
 * @date 2016年4月20日
 * 
 */
@Service
public class RestfulTestServiceImpl implements RestfulTestService {

    @Autowired
    private RestfulTestOperation restfulTestOperation;
    
    public String restfulTestMethod() {
        ParamEntity info = new ParamEntity();
        Map<String, Map<String, Object>> dataMap = new HashMap<String, Map<String, Object>>();
        Map<String, Object> userEntity = new HashMap<String, Object>();
        userEntity.put("default_project_id", "pid");
        userEntity.put("description", "user.getDescription()");
        userEntity.put("domain_id", "default");
        userEntity.put("email", "user.getEmail()");
        userEntity.put("enabled", true);
        userEntity.put("name", "user.getUsername()");
        userEntity.put("password", "user.getStrPassword()");
        dataMap.put("user", userEntity);
        String data = JSON.toJSONString(dataMap);
        info.setData(data);
        
        info.setIpaddr("127.0.0.1");
        info.setPort("808");
        ResponseEntity<String> response = restfulTestOperation.restfulTestMethod(info);
        // 当创建某个用户失败时
        if (response == null || !response.getStatusCode().equals(HttpStatus.CREATED)) {
            throw new RuntimeException("调用接口创建用户失败!");
        } else {
            JSONObject object = JSONObject.parseObject(response.getBody().toString());
            JSONObject userJson = JSONObject.parseObject(object.getString("user"));
            System.out.println("解析body为json后的用户id为:"+userJson.getString("id"));
            //return userJson.getString("id");
            return response.getBody().toString();
        }
    }

}

⑦ controller层测试类,包含调用入口和服务方法,此处为静态返回,可以根据具体业务书写,和常见代码一样

package xiaochangwei.zicp.net.web.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;

import xiaochangwei.zicp.net.entity.TestEntity;
import xiaochangwei.zicp.net.service.restful.RestfulTestService;

/**
 * @author http://www.cnblogs.com/xiaochangwei
 * @date 2016年4月20日
 * 
 */
@Controller
@RequestMapping("restful")
public class RestfulTestController {

    @Autowired
    private RestfulTestService restfulTestService;

    /**
     * 处理restClient请求的的方法体
     */
    @RequestMapping("restfulService")
    public ResponseEntity<String> testRestClientAdd(
            @RequestHeader("Accept") String Accept, @RequestBody String userStr) {
        System.out.println("接收到的请求信息-Accept:" + Accept);
        System.out.println("接收到的请求信息-body:" + userStr);
        // 可以根据请请进行业务处理,这里略了 只是打印出来确定消息传递过来没

        // 返回处理结果给调用者
        TestEntity en = new TestEntity();
        en.setId(1);
        en.setName("name1");

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("user", en);
        String body = JSON.toJSONString(map);
        System.out.println("准备返回给调用者的body content:" + body);

        ResponseEntity<String> responseEntity = new ResponseEntity<String>(
                body, HttpStatus.CREATED);
        return responseEntity;
    }

    /**
     * 调用rest接口方法进行rpc调用
     */
    @RequestMapping("restfulClientCall")
    public @ResponseBody String t() {
        return restfulTestService.restfulTestMethod();
    }
}

 

⑧ 见证奇迹的时候又到了

输入  http://www.xiaochangwei.com:808/project-web/restful/restfulClientCall  进行调用,restful会访问我们这个controller中的restfulService

同时控制台也看到如下信息,证明我们的调用成功

 

至此,restful使用讲解完毕,不过需要提醒的时,restful是通过http协议进行传输的,同等条件下速度比tcp慢,所以实时性较高请使用tcp实现的rpc或者采用jms

相关技术均可以通过我的博客了解学习到,请锁定关注。

 

posted @ 2016-04-21 22:50  肖哥哥  阅读(21796)  评论(4编辑  收藏  举报
生命不息  奋斗不止  每天进步一点点