Restful 介紹及SpringMVC+restful 實例講解

 

 

restful不是一個框架,稱爲一種編碼更煩更貼切吧,其核心類位於spring-web.jar中,即RestTemplate.classjava

restful是rpc經過http協議的一種實現方式,和webservice同樣,請參閱個人其餘文章web

 

今天我將在springmvc環境中進行演示,首先請看我其餘博客文章下載整理好的源碼,整理好的源碼能夠直接用於商業項目開發spring

整理好的代碼項目結構以下:apache

本次講的restful大體以下json

 

文采很差,開始貼代碼:restful

① 常量工具類,用於保存http、:、?、=、&這些的mvc

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);
    }
}

② 模塊枚舉定義類app

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;

 ④ 核心調用類dom

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

相關技術都可以經過個人博客瞭解學習到,請鎖定關注。

相關文章
相關標籤/搜索