1. 程式人生 > >JAVA RPC遠端呼叫伺服器實現使用者登入、註冊

JAVA RPC遠端呼叫伺服器實現使用者登入、註冊

先來百科掃盲 : 什麼是 RPC(反正我也剛看的)

RPC(Remote Procedure Call)—遠端過程呼叫,它是一種通過網路從遠端計算機程式上請求服務,而不需要了解底層網路技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通訊程式之間攜帶資訊資料。在OSI網路通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網路分散式多程式在內的應用程式更加容易。


有圖就不看字這裡寫圖片描述

分層來實現

Client 客戶端; Server 服務端; Controller 解析客戶端請求; Service 儲存方法, 實現Dao層介面; Dao 對資料庫操作; 利用c3p0 資料庫連線池連線資料庫(繞口)
下面程式碼長又長(主要客戶端封裝Bean多), 建議複製貼上, 建立多個類(分界線已標出)

eclipse包結構

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

}

囉裡囉嗦那麼多 , 看著就頭痛, 如何使用動態代理完善一下呢?

思考許久,還是用框架吧