JAVA RPC遠端呼叫伺服器實現使用者登入、註冊
阿新 • • 發佈:2018-11-09
先來百科掃盲 : 什麼是 RPC(反正我也剛看的)
RPC(Remote Procedure Call)—遠端過程呼叫,它是一種通過網路從遠端計算機程式上請求服務,而不需要了解底層網路技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通訊程式之間攜帶資訊資料。在OSI網路通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網路分散式多程式在內的應用程式更加容易。
有圖就不看字
分層來實現
Client 客戶端; Server 服務端; Controller 解析客戶端請求; Service 儲存方法, 實現Dao層介面; Dao 對資料庫操作; 利用c3p0 資料庫連線池連線資料庫(繞口)
下面程式碼長又長(主要客戶端封裝Bean多), 建議複製貼上, 建立多個類(分界線已標出)
Client 服務端:
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
import com.doit.bean.Request;
import com.doit.bean.Response;
import com.doit.bean.User;
public class Client {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
try {
Socket s = new Socket("127.0.0.1", 30000);
OutputStream out = s.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
Request req = new Request();//需要建立Request類,包含方法型別和引數等,序列化傳送
User user = new User();
user.setUserName("金剛葫蘆娃");//註冊 姓名
user.setPassWord("123456");//註冊 密碼
user.setPhoneNum("15000000000");//註冊 手機號
req.setClassName("com.doit.service.ServiceImpl");// 全類名
req.setMethodName("regist");//客戶端發出註冊指令
req.setParameterTypes(new Class[] { User.class });
req.setParameterValues(new Object[] { user });
oos.writeObject(req);//使用Object輸出流傳送 Request
InputStream in = s.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
Response readObject = (Response) ois.readObject();
System.out.println(readObject.getDesc());
oos.close();
out.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
----------
import java.io.Serializable;
/**
* Request 實現序列化
*/
public class Request implements Serializable{
private static final long serialVersionUID = 1L;
private String className;
private String methodName;
private Class[] parameterTypes;
private Object[] parameterValues;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Class[] getParameterTypes() {
return parameterTypes;
}
public void setParameterTypes(Class[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
public Object[] getParameterValues() {
return parameterValues;
}
public void setParameterValues(Object[] parameterValues) {
this.parameterValues = parameterValues;
}
----------
import java.io.Serializable;
/**
* Response 實現序列化,實現向客戶端友好響應效果
*/
public class Response implements Serializable{
private static final long serialVersionUID = 1L;
private Object object;
private int status;
private String desc;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Response [object=" + object + ", status=" + status + ", desc=" + desc + "]";
}
}
----------
/**
*javaBean 封裝User類 裡面包括所需的使用者基本資訊, 並實現序列化
*/
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String userName;
private String passWord;
private String phoneNum;
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;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
@Override
public String toString() {
return "User [userName=" + userName + ", passWord=" + passWord + ", phoneNum=" + phoneNum + "]";
}
Server服務端:
複製貼上 客戶端的Request 、 Response 、User 三個類(保證服務端和客戶端這三個檔案類名和內容相同。)
此處不再寫上述3個
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import com.doit.bean.Request;
import com.doit.bean.Response;
/**
* 服務端 接收 客戶端 , 反射Request中資訊, 確定呼叫方法
*/
public class Server {
private static final Object User = null;
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(30000);
while(true) {
Socket s = ss.accept();
InputStream ins = s.getInputStream();
ObjectInputStream ois = new ObjectInputStream(ins);
Request readObject = (Request) ois.readObject();
/*
* 反射獲取 Request 中的資訊
*/
//獲取類名
String className = readObject.getClassName();
//獲取方法名
String methodName = readObject.getMethodName();
//獲取引數型別
Class[] parameterTypes = readObject.getParameterTypes();
//獲取 引數(實參)
Object[] parameterValues = readObject.getParameterValues();
//呼叫伺服器中本地方法
Class<?> request = Class.forName(className);
Method method = request.getMethod(methodName,parameterTypes);
//方法呼叫, 建立反射Class的物件 newInstance
Response invoke = (Response)method.invoke(request.newInstance(),parameterValues) ;
//System.out.println(invoke);
OutputStream out = s.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(invoke);
oos.flush();
s.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
----------
import com.doit.bean.Response;
import com.doit.bean.User;
/**
* 建立Service 介面 方法包括使用者登入和註冊
*/
public interface Service {
public Response login(User user) throws Exception;
public Response regist(User user) throws Exception;
}
----------
import com.doit.bean.User;
/**
* Dao 層 , 建立呼叫伺服器介面
*/
public interface Dao {
//註冊
public void insert(User user) throws Exception;
public void delete() throws Exception;
public void update() throws Exception;
//登入
public User getUserByNameAndPassword(User user) throws Exception;
public User selectByname(User user)throws Exception;
}
----------
/**
* Dao 層 , 建立實現Dao介面DaoImpl類
*/
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import com.doit.bean.User;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DaoImpl implements Dao {
static QueryRunner runner=null;
static {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
runner = new QueryRunner(dataSource);
}
/*
* 增加資料(註冊)
*/
@Override
public void insert(User user) throws Exception {
String sql="insert into usersinfo values(null,?,?,?)" ;
runner.update(sql, user.getUserName(),user.getPassWord(),user.getPhoneNum());
}
/*
* 登入資料庫
*/
@Override
public User getUserByNameAndPassword(User user) throws Exception {
String sql="select * from usersinfo where name = ? and passWord = ?";
User query = runner.query(sql, new BeanHandler<User>(User.class),user.getUserName(),user.getPassWord());
return query;
}
@Override //實現使用者註冊時反應使用者名稱是否存在功能
public User selectByname (User user) throws Exception {
String sql ="select * from usersinfo where name = ?";
User query = runner.query(sql, new BeanHandler<User>(User.class),user.getUserName());
return query;
}
}
----------
import com.doit.bean.Response;
import com.doit.bean.User;
import com.doit.dao.Dao;
import com.doit.dao.DaoImpl;
/*
* Service 介面的實現類, 該類中包含對資料庫操作的判斷,並返回給客戶端
*/
public class ServiceImpl implements Service {
Dao daoImpl = new DaoImpl();
@Override
public Response login(User user) throws Exception {
Response r = new Response();
User res = null;
if (user != null) {// 如果提供資訊不為空, 執行登入
res = daoImpl.getUserByNameAndPassword(user);
if (res == null) {
r.setStatus(500);
r.setDesc("對不起,你的使用者名稱或者密碼錯誤");
} else {
r.setStatus(200);
r.setDesc("歡迎登入");
r.setObject(res);
}
} else {
r.setStatus(500);
}
return r;
}
@Override
public Response regist(User user) throws Exception {
Response r = new Response();
if(user.getUserName()!=null&&user.getUserName().length()>0) {//解決什麼都不輸入也能進行註冊的問題
User u = daoImpl.selectByname(user);
if (u == null) {// 如果資料庫中不存在要註冊名字,則進行註冊
daoImpl.insert(user);
r.setDesc("註冊成功");
} else {// 如果資料庫中存在要註冊的名字, 不進行註冊
r.setDesc("哇呀,這個名字已經被搶,換個試試");
}
}else {//解決什麼都不輸入也能進行註冊的問題
r.setDesc("請認真對待自己的使用者名稱!");
}
return r;
}
}
囉裡囉嗦那麼多 , 看著就頭痛, 如何使用動態代理完善一下呢?
思考許久,還是用框架吧