程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 基於Rest服務實現的RPC,Rest服務實現RPC

基於Rest服務實現的RPC,Rest服務實現RPC

編輯:JAVA綜合教程

基於Rest服務實現的RPC,Rest服務實現RPC


  前言:現在RPC成熟的框架已經很多了,比喻Motan和Dubbo,但是今天我這裡提供一種基於Rest服務的Rpc。和上一篇連著的http://www.cnblogs.com/LipeiNet/p/5856414.html

1:原理

首先我們要建立一個Rest服務,如果其他應用程序想要獲取這個服務的資源就只需要一個URI就可以了。但是由於內部程序的調用我們在通過URI獲取json然後在自己處理很不方便,也不是很合適,那麼我們就需要利用一個中間層,把訪問Rest服務返回的資源重新包裝,然後其他工程只需要調用這個rpc工程即可。如下圖

2:實現Rest服務

2.1:定義一個用於返回給消費者的實現對象(自己約定的)

public class ResponseBean implements Serializable{
    private static final long serialVersionUID = -1L;
    public static final int SUCCESS = 10;
    public static final int FAILURE = 20;
    public static final int LOCKED = 30;
    public static final int EXCEPTION = 40;
    private int returnCode;//返回給消費者的編碼(0表示調用成功,1表示調用失敗)
    private String returnMsg;//返回給消費者錯誤信息
    private int dataCount;//用於返回int類型
    private String returnData;//用戶返回json
    private Object returnObject;//用於返回對象

    public ResponseBean() {
    }

    public ResponseBean(int returnCode, String returnMsg) {
        this.returnCode = returnCode;
        this.returnMsg = returnMsg;
    }

    public Object getReturnObject() {
        return this.returnObject;
    }

    public void setReturnObject(Object returnObject) {
        this.returnObject = returnObject;
    }

    public int getDataCount() {
        return this.dataCount;
    }

    public void setDataCount(int dataCount) {
        this.dataCount = dataCount;
    }

    public String getReturnData() {
        return this.returnData;
    }

    public void setReturnData(String returnData) {
        this.returnData = returnData;
    }

    public int getReturnCode() {
        return this.returnCode;
    }

    public void setReturnCode(int returnCode) {
        this.returnCode = returnCode;
    }

    public String getReturnMsg() {
        return this.returnMsg;
    }

    public void setReturnMsg(String returnMsg) {
        this.returnMsg = returnMsg;
    }
}

2.2:定一個供外部請求的ApiService

public interface ApiService {
     String getToken();
     ResponseBean add(String reqJson);
}
public class ApiServiceImpl implements ApiService {
    private static final Log log = LogFactory.getLog(ApiServiceImpl.class);
    @Autowired
    private UserDao userDao;
    private String token;//供調用rpc校驗使用

    public String getToken() {
        return token;
    }

    public ResponseBean add(String reqJson) {
        ResponseBean responseBean = new ResponseBean(ResponseBean.SUCCESS, "調用成功");
        try {
            Map map = JsonUtil.g.fromJson(reqJson, HashMap.class);
            String username = map.get("username").toString();
            String password = map.get("password").toString();
            String realname = map.get("realname").toString();
            Long userroleid =Double.valueOf(map.get("userroleid").toString()).longValue() ;
            UserBean userBean = new UserBean();
            userBean.setCreatedate(new Date());
            userBean.setPassword(password);
            userBean.setUserroleid(userroleid);
            userBean.setRealname(realname);
            userBean.setUsername(username);
            int count = userDao.add(userBean);
            responseBean.setReturnData(JsonUtil.g.toJson(count));
            responseBean.setReturnCode(10);
        } catch (Exception e) {
            log.error(e.getStackTrace());
            responseBean.setReturnCode(11);
            responseBean.setReturnMsg("服務器異常");
        }
        return responseBean;
    }

    public void setToken(String token) {
        this.token = token;//用於設置token(用來驗證消費者的token是否是服務器的token)
    }
}

2.3:定義http請求的入口,需要3個參數token(進行安全認證)、m(請求方法名)、reqJson(請求的參數)

@Controller
@RequestMapping(value = "/api")
public class ApiController {
    private static final Log log = LogFactory.getLog(ApiController.class);
    @Autowired
    private ApiService apiService;

    /**
     * 系統對外公開調用方法
     *
     * @param m       接口方法名
     * @param reqJson 請求參數
     * @param token   請求token
     * @return
     */
    @RequestMapping(value = "/exec", method = RequestMethod.POST)
    @ResponseBody
    public Object exec(@RequestParam(value = "m", required = true) String m,
                       @RequestParam(value = "reqJson", required = true) String reqJson,
                       @RequestParam(value = "token", required = true) String token) {
         log.info(String.format("m=%s,reqJson=%s,token=%s", m, reqJson, token));
        Class c = apiService.getClass();
        Method method = null;
        ResponseBean responseBean = null;
        if (!token.equals(apiService.getToken())) {
            log.error("token校驗失敗,token=" + token);
            responseBean = new ResponseBean(ResponseBean.FAILURE, "校驗失敗");
            return responseBean;
        }
        try {
            method = c.getMethod(m, String.class);//利用反射找到對應的方法
        } catch (Exception e) {
            log.error("m參數錯誤,m=" + m + ";req=" + reqJson, e);
            responseBean = new ResponseBean(ResponseBean.FAILURE, "m參數錯誤m=" + m);
            return responseBean;
        }
        if (StringUtils.isEmpty(reqJson)) {
            log.error("reqJson為空");
            responseBean = new ResponseBean(ResponseBean.FAILURE, "reqJson為空");
            return responseBean;
        }
        try {
            Object json = method.invoke(apiService, reqJson);
            return json;
        } catch (Exception e) {
            log.error("處理異常,m=" + m + ";req=" + reqJson, e);
            responseBean = new ResponseBean(ResponseBean.FAILURE, "服務器處理異常");
            return responseBean;
        }
    }
}

通過上面我們就實現了一個供消費者調用的rest服務。

3:RPC對rest服務進行包裝

3.1:定義消費者需要的webService

public interface WebService {
    ResponseBean add(UserBean userBean);
}

實現webService

public class WebserviceImpl implements WebService {
    private final static Log log = LogFactory.getLog(WebserviceImpl.class);
    private String url;//供消費者設置的url地址
    private String token;//供消費者設置的url

    public void setUrl(String url) {
        this.url = url;
    }

    public void setToken(String token) {
        this.token = token;
    }

    @Override
    public ResponseBean add(UserBean userBean) {
        Map<String, String> map = new HashMap();
        ResponseBean rb = null;
        map.put("token", token);
        map.put("reqJson", JsonUtil.g.toJson(userBean));
        String reqUrl = url + "?m=add";//在這裡進行設置你需要訪問哪個方法
        log.debug(reqUrl);
        try {
            String str = HttpClientUtil.executeHttpRequestUTF(reqUrl, map);//訪問資源獲取返回的json
            log.debug("add return data:" + str);
            rb = JsonUtil.g.fromJson(str, ResponseBean.class);//對json進行轉換
            log.debug("getPromInfo return Regions data" + reqUrl);
            return rb;
        } catch (Exception e) {
            rb = new ResponseBean();
            rb.setReturnObject(e);
            log.debug(e.getStackTrace());
            return rb;
        }
    }
}

然後對rpc進行打包發布,其他應用程序就可以直接使用了。

4:配置

在applicationconfig中加入

<mvc:annotation-driven/>
<mvc:default-servlet-handler />
<mvc:annotation-driven /> 會自動注冊DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter 兩個bean否則會出現異常

<bean id="ApiService" class="com.lp.rpc.impl.ApiServiceImpl">
    <property name="token" value="41729ff3-3406-4fc5-aeca-04f98892999b"></property>
</bean>
消費者配置:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="webService" class="com.lp.rpc.impl.WebserviceImpl">
    <property name="url" value="http://192.168.0.101:8088/api/exec"></property>
    <property name="token" value="41729ff3-3406-4fc5-aeca-04f98892999b"></property>
</bean>
</beans>

5:開啟一個項目把rpc項目引進調用

public class AppMain {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml");
        WebService webService = (WebService) context.getBean("webService");
        UserBean userBean = new UserBean();
        userBean.setUsername("lisi");
        userBean.setPassword("123456");
        userBean.setRealname("李四");
        userBean.setUserroleid(2);
        userBean.setCreatedate(new Date());
        ResponseBean result = webService.add(userBean);
        if (StringUtils.equals(result.getReturnData().toString(),"1")){
            System.out.print("添加成功");
        }
    }
}

6:總結

以上級別能完成不同項目之間的調用了

優點:簡單上手快,可以自己控制,效率也可以。

缺點:安全性低,需要維護url,有時候別人服務反復開啟時候會出現調用不到的情況。

 源碼地址

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved