前言:現在RPC成熟的框架已經很多了,比喻Motan和Dubbo,但是今天我這裡提供一種基於Rest服務的Rpc。和上一篇連著的http://www.cnblogs.com/LipeiNet/p/5856414.html
首先我們要建立一個Rest服務,如果其他應用程序想要獲取這個服務的資源就只需要一個URI就可以了。但是由於內部程序的調用我們在通過URI獲取json然後在自己處理很不方便,也不是很合適,那麼我們就需要利用一個中間層,把訪問Rest服務返回的資源重新包裝,然後其他工程只需要調用這個rpc工程即可。如下圖

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.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進行打包發布,其他應用程序就可以直接使用了。
在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>
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("添加成功");
}
}
}
以上級別能完成不同項目之間的調用了
優點:簡單上手快,可以自己控制,效率也可以。
缺點:安全性低,需要維護url,有時候別人服務反復開啟時候會出現調用不到的情況。