今天咋們看的這個項目源碼是一個微博客戶端,和服務端通信用socket寫的,項目名稱:口袋微博,和前面那個項目不一樣,這個項目略難一點,不過不要緊,讓咱們一塊兒來學習學習吧。java
按照使用流程,首先是註冊頁面,所以咱們來寫註冊頁面,先把註冊頁面的佈局寫了:android
佈局寫好之後,咱們須要給這些佈局添加點擊事件(主要是註冊),經過自定義一個MyConnection指定地址和端口號鏈接socket獲得DataOutputStream和一個DataInputStream,把要發送的註冊信息封裝好(這裏封裝用的是消息頭+分隔符的形式)把消息發給服務端,而後經過DataInputStream讀取服務端返回的結果,若是服務端返回結果的請求頭爲<#REG_SUCCESS#>表明註冊成功,同時用一個變量記住返回的結果,不然就是註冊失敗。數據庫
註冊代碼以下:服務器
- /**
- * 方法:鏈接服務器,進行註冊
- */
- public void register(){
- new Thread(){
- public void run(){
- Looper.prepare();
- //1.得到用戶輸入的數據並進行驗證
- EditText etName = (EditText)findViewById(R.id.etName); //得到暱稱EditText對象
- EditText etPwd1 = (EditText)findViewById(R.id.etPwd1); //得到密碼EditText對象
- EditText etPwd2 = (EditText)findViewById(R.id.etPwd2); //得到確認密碼EditText對象
- EditText etEmail = (EditText)findViewById(R.id.etEmail); //得到郵箱EditText對象
- EditText etStatus = (EditText)findViewById(R.id.etStatus); //得到心情EditText對象
- String name = etName.getEditableText().toString().trim(); //得到暱稱
- String pwd1 = etPwd1.getEditableText().toString().trim(); //得到密碼
- String pwd2 = etPwd2.getEditableText().toString().trim(); //得到確認密碼
- String email = etEmail.getEditableText().toString().trim(); //得到郵箱
- String status = etStatus.getEditableText().toString().trim(); //得到狀態
- if(name.equals("") || pwd1.equals("") || pwd2.equals("") || email.equals("") || status.equals("")){
- Toast.makeText(RegActivity.this, "請將註冊信息填寫完整", Toast.LENGTH_LONG).show();
- return;
- }
- if(!pwd1.equals(pwd2)){ //判斷兩次輸入的密碼是否一致
- Toast.makeText(RegActivity.this, "兩次輸入的密碼不一致!", Toast.LENGTH_LONG).show();
- return;
- }
- //2.鏈接服務器開始傳數據
- try{
- mc = new MyConnector(SERVER_ADDRESS, SERVER_PORT);
- String regInfo = "<#REGISTER#>"+name+"|"+pwd1+"|"+email+"|"+status;
- mc.dout.writeUTF(regInfo);
- String result = mc.din.readUTF();
- pd.dismiss();
- if(result.startsWith("<#REG_SUCCESS#>")){ //返回信息爲註冊成功
- result= result.substring(15); //去掉信息頭
- uno = result; //記錄用戶的ID
- myHandler.sendEmptyMessage(0); //發出Handler消息
- Toast.makeText(RegActivity.this, "註冊成功!", Toast.LENGTH_LONG).show();
- }
- else{ //註冊失敗
- Toast.makeText(RegActivity.this, "註冊失敗!請重試!", Toast.LENGTH_LONG).show();
- }
- }
- catch(Exception e){
- e.printStackTrace();
- }
- }
- }.start();
- }
接下來咱們來寫服務端的代碼,由於服務端用的socket,所以須要一個入口函數,這個入口在Server.java文件中,經過它開啓一個服務線程:socket
- public class Server{
- public static void main(String args[]){
- try{
- ServerSocket ss = new ServerSocket(8888);
- ServerThread st = new ServerThread(ss);
- st.start();
- System.out.println("Listening...");
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
咱們轉到這個線程類裏面,發現實現是經過調用serverSocket的accept()方法,監聽客戶端請求。對於請求過來的數據,專門寫一個代理類ServerAgent.java來處理。ide
- package wpf;
-
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.net.SocketException;
-
- public class ServerThread extends Thread{
- public ServerSocket ss; //聲明ServerSocket對象
- public boolean flag = false;
-
- public ServerThread(ServerSocket ss){ //構造器
- this.ss = ss;
- flag = true;
- }
- public void run(){
- while(flag){
- try{
- Socket socket = ss.accept();
- ServerAgent sa = new ServerAgent(socket);
- sa.start();
- }
- catch(SocketException se){
- try{
- ss.close();
- ss = null;
- System.out.println("ServerSocket closed");
- }catch(Exception ee){
- ee.printStackTrace();
- }
- }
- catch(Exception e){
- e.printStackTrace();
- }
- }
- }
- }
咱們來看ServerAgent是怎麼實現的。函數
代理線程經過構造函數拿到數據輸入和輸出流,而後在run方法裏面處理用戶請求。接下來就是對請求頭的判斷,咱們這裏先只講註冊請求,收到的是註冊請求,解析用戶發過來的數據,而後經過寫一個數據庫工具類DBUtil類處理用戶發送過來的數據。並將處理結果返回給客戶端,而後客戶端經過判斷從服務器獲取的請求結果更新ui界面。兩個主要的方法:工具
- public ServerAgent(Socket socket){
- this.socket = socket;
- try {
- this.din = new DataInputStream(socket.getInputStream());
- this.dout = new DataOutputStream(socket.getOutputStream());
- flag =true;
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- public void run(){
- while(flag){
- try {
- String msg = din.readUTF(); //接收客戶端發來的消息
- // System.out.println("收到的消息是:"+msg);
- if(msg.startsWith("<#REGISTER#>")){ //消息爲用戶註冊
- msg = msg.substring(12); //得到字符串值
- String [] sa = msg.split("\\|"); //切割字符串
- String regResult = DBUtil.registerUser(sa[0], sa[1], sa[2], sa[3], "1");
- if(regResult.equals(REGISTER_FAIL)){ //註冊失敗
- dout.writeUTF("<#REG_FAIL#>");
- }
- else{
- dout.writeUTF("<#REG_SUCCESS#>"+regResult);
- }
- }
- }
因而,咱們轉到DbUtil類裏面,看書怎麼保存到數據庫中的。咱們發現存儲使用通常存儲方式,只是裏面有設置存儲編碼方式,還用到了prepareStatement。處理結束返回處理結果,若是鏈接爲null返回鏈接失敗,若是保存到數據庫成功就返回註冊完的用戶id,不然返回註冊失敗。完了以後不要忘了釋放資源。oop
//方法:註冊用戶佈局
- public static String registerUser(String u_name,String u_pwd,String u_email,String u_state,String h_id){
- String result=null;
- Connection con = null; //聲明數據庫鏈接對象
- PreparedStatement ps = null; //聲明語句對象
- try{
- con = getConnection();
- if(con == null){ //判斷是否成功獲取鏈接
- result = CONNECTION_OUT;
- return result; //返回方法的執行
- }
- ps = con.prepareStatement("insert into user(u_no,u_name,u_pwd,u_email,u_state,h_id)" +
- "values(?,?,?,?,?,?)"); //構建SQL語句
- String u_no = String.valueOf(getMax(USER)); //得到分配給用戶的賬號
- u_name = new String(u_name.getBytes(),"ISO-8859-1"); //轉成ISO-8859-1以插入數據庫
- u_state = new String(u_state.getBytes(),"ISO-8859-1"); //轉成ISO-8859-1以插入數據庫
- int no = Integer.valueOf(u_no);
- int hid = Integer.valueOf(h_id);
- ps.setInt(1, no); //設置PreparedStatement的參數
- ps.setString(2, u_name);
- ps.setString(3, u_pwd);
- ps.setString(4, u_email);
- ps.setString(5, u_state);
- ps.setInt(6,hid);
- int count = ps.executeUpdate(); //執行插入
- if(count == 1){ //若是插入成功
- result = u_no; //得到玩家的賬號
- }
- else{ //若是沒有插入數據
- result = REGISTER_FAIL; //得到出錯信息
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- finally{
- try{
- if(ps != null){
- ps.close();
- ps = null;
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- try{
- if(con != null){
- con.close();
- con = null;
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- return result;
- }
接下來即是客戶端處理服務端返回數據:
客戶端處理完服務端發過來的數據,就經過handler更新界面,讓進入我的中心這個按鈕可見,同時拿到用戶id轉到我的中心頁面。這樣,一個用戶註冊的模塊寫好了。
- Handler myHandler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what){
- case 0:
- View linearLayout = (LinearLayout)findViewById(R.id.regResult); //得到線性佈局
- linearLayout.setVisibility(View.VISIBLE); //設置可見性
- EditText etUno = (EditText)findViewById(R.id.etUno);
- etUno.setText(uno);
- break;
- }
- super.handleMessage(msg);
- }
- };
下一篇介紹用戶登陸時如何實現的。