自己动手编写仿QQ的app -1注册界面by sdust iot zhl

来源:互联网 发布:乐清市知临学校招聘 编辑:程序博客网 时间:2024/05/23 15:34

协议:tcp/ip 协议
架构:c/s 架构
数据库:mysql
服务器端接口语言 :python
客户端语言:安卓

注册:服务器端创建套接字,获取客户端发来的json数据,解析完后存入数据库

首先安装服务器端mysql 数据库 ,这里我直接安装了 phpstudy
然后 进入cmd,mysql - u root - p 输入密码登录数据库
然后进入 test 数据库
创建如下的数据表

mysql> create table users (    ->  `id` int not null auto_increment ,    -> `account` char(10) not null,    -> `password` char(10) not null,    ->  primary key (`id`),    -> unique key( `account`)    -> );

即创建了一个 主键为id 拥有两个栏目,account (账户)与password(密码)的表用于储存用户账户密码,并且设置各栏目非空,主键自增,account(账户)键值唯一,即用户名唯一

然后开始编写服务器端代码

#coding:utf-8import MySQLdb ,socket,threading ,time,jsonfrom json import *class myThread (threading.Thread):    def __init__(self):        threading.Thread.__init__(self)    def run(self):        print "Starting " + self.name        try:            data=conn.recv(1024)            print data            dict=json.loads(data)            dict = eval(dict)            threadLock.acquire()            cur=conne.cursor()            account=dict['account']            password = dict['password']            tuple = (account,password)            sql = " INSERT INTO users (account,password) VALUES(%s,%s)";            cur.execute(sql,tuple)            conn.send("写入成功")            cur.close()            print("succeed in writing")            threadLock.release()        finally:            conn.close()conne=MySQLdb.connect(host='127.0.0.1',user='root',passwd='ONS2015',db='test',port=3306)threadLock = threading.Lock()HOST='127.0.0.1'PORT=2333s= socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.bind(('127.0.0.1',2333))s.listen(5)while (1):    conn,addr = s.accept()    print'Connected by',addr    # 接受客户端端的连接后,就开启一个线程处理客户端的数据    thread = myThread()    thread.start()

其中

dict=json.loads(data)
dict = eval(dict)
是将json数据流转化为string,再转化为dict ,从而接下来对其进行操作

而conne=MySQLdb.connect(host=’127.0.0.1’,user=’root’,passwd=’ONS2015’,db=’test’,port=3306)
是数据库连接操作

sql = ” INSERT INTO users (account,password) VALUES(%s,%s)”;
cur.execute(sql,tuple)
则是向数据库中插入数据的操作

客户端先使用 python 进行简单测试,代码如下:

import MySQLdb ,socket,threading ,time,jsonfrom json import *HOST='127.0.0.1'PORT=2333s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect(('127.0.0.1',2333))dict="{'account':'doge','password':'123'}"d=json.dumps(dict)s.sendall(d)data=s.recv(1024)print data

主要使用了d=json.dumps(dict)将dict转化为json字符串

服务器端输出如下:

C:\Python27\python.exe E:/代码文件/python/client_test.pyConnected by ('127.0.0.1', 59171)Starting Thread-1"{'account':'doge','password':'123'}"succeed in writing

客户端如下:

C:\Python27\python.exe E:/代码文件/python/client.py写入成功Process finished with exit code 0

接下来开始写安卓端的界面,这是第一次做出来的效果图

其中UI,即xml文件上遇到的问题如下:
1.密码输入只以 * 显示

android:inputType="textPassword"

2.设置一个隐藏的提示功能的文本

android:hint="请输入账户"

3.限制输入只能为字母数字下划线
以及长度限制最高为10
android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"
android:maxLength="10"

4.设置隐藏的提示框,即设置一个字体颜色,内容为空的textview ,用于在接下来提示输入

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#f4f4f3"    android:orientation="vertical"><ImageView    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:contentDescription="dp"    android:src="@mipmap/dp"    android:layout_weight="0.15"/>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="0dp"        android:layout_weight="0.05"        android:orientation="horizontal"        >        <TextView            android:layout_width="0sp"            android:layout_height="match_parent"            android:text="账户"            android:id="@+id/register_tv1"            android:layout_weight="0.02"            android:gravity="center"            android:textSize="20sp"            />        <EditText            android:layout_width="0sp"            android:layout_height="match_parent"            android:hint="请输入账户"            android:id="@+id/register_account"            android:layout_weight="0.07"            android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"            android:maxLength="10"            />    </LinearLayout>    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/register_warm1"        android:text=""        android:layout_weight="0.0005"        android:gravity="center"        android:textSize="20sp"        android:textColor="#fc4984"        android:visibility="visible"        />    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="0dp"        android:layout_weight="0.05"        android:orientation="horizontal"        >        <TextView            android:layout_width="0sp"            android:layout_height="match_parent"            android:text="密码"            android:id="@+id/register_tv2"            android:layout_weight="0.02"            android:gravity="center"            android:textSize="20sp"            />        <EditText            android:layout_width="0sp"            android:layout_height="match_parent"            android:hint="请输入密码"            android:id="@+id/register_password1"            android:layout_weight="0.07"            android:inputType="textPassword"            android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"            android:maxLength="10"            />    </LinearLayout>    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text=""        android:id="@+id/register_warm2"        android:layout_weight="0.0005"        android:gravity="center"        android:textSize="20sp"        android:textColor="#fc4984"        android:visibility="visible"        />    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="0dp"        android:layout_weight="0.05"        android:orientation="horizontal"        >        <TextView            android:layout_width="0sp"            android:layout_height="match_parent"            android:text="密码"            android:id="@+id/register_tv3"            android:layout_weight="0.02"            android:gravity="center"            android:textSize="20sp"            />        <EditText            android:layout_width="0sp"            android:layout_height="match_parent"            android:hint="请再次输入密码"            android:id="@+id/register_password2"            android:layout_weight="0.07"            android:inputType="textPassword"            android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"            android:maxLength="10"            />    </LinearLayout>    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text=""        android:id="@+id/register_warm3"        android:layout_weight="0.0005"        android:gravity="center"        android:textSize="20sp"        android:textColor="#fc4984"        android:visibility="visible"        />    <LinearLayout    android:layout_width="fill_parent"    android:layout_height="0dp"    android:layout_weight="0.05"    android:orientation="horizontal"    >        <TextView            android:layout_width="0sp"            android:layout_height="wrap_content"            android:text="性别"            android:textSize="20sp"            android:gravity="center"            android:layout_weight="0.29"/>    <RadioGroup        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_weight="0.7">        <LinearLayout            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:orientation="horizontal">            <RadioButton            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="男"            android:layout_weight="0.5"/>            <RadioButton            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="女"            android:layout_weight="0.5"/>        </LinearLayout>    </RadioGroup></LinearLayout>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="0dp"        android:layout_weight="0.1"        android:orientation="horizontal"        >    <Button    android:layout_width="0dp"    android:layout_height="wrap_content"    android:text="完成注册"    android:id="@+id/register_bt"    android:layout_weight="0.005"    android:background="#1fb2f6"    android:textColor="#fefefe"    android:textSize="20sp"        />    </LinearLayout></LinearLayout>

从中获得了很多学习经验,
如:控件可以嵌套LinearLayout,从而形成各种风格的布局
字体大小要设置为sp单位
可以设置RadioGroup 管理RadioButton

这是最终的客户端代码

package doge.dp.test;import android.os.Bundle;import android.os.Looper;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.NavigationView;import android.support.design.widget.Snackbar;import android.support.v4.view.GravityCompat;import android.support.v4.widget.DrawerLayout;import android.support.v7.app.ActionBarDrawerToggle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.text.Editable;import android.text.TextWatcher;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.Socket;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;public class MainActivity extends AppCompatActivity        implements NavigationView.OnNavigationItemSelectedListener {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);        setSupportActionBar(toolbar);        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);        fab.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)                        .setAction("Action", null).show();            }        });        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);        drawer.setDrawerListener(toggle);        toggle.syncState();        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);        navigationView.setNavigationItemSelectedListener(this);        SetListener();    }    @Override    public void onBackPressed() {        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);        if (drawer.isDrawerOpen(GravityCompat.START)) {            drawer.closeDrawer(GravityCompat.START);        } else {            super.onBackPressed();        }    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        //noinspection SimplifiableIfStatement        if (id == R.id.action_settings) {            return true;        }        return super.onOptionsItemSelected(item);    }    @SuppressWarnings("StatementWithEmptyBody")    @Override    public boolean onNavigationItemSelected(MenuItem item) {        // Handle navigation view item clicks here.        int id = item.getItemId();        if (id == R.id.nav_camera) {            // Handle the camera action        } else if (id == R.id.nav_gallery) {        } else if (id == R.id.nav_slideshow) {        } else if (id == R.id.nav_manage) {        } else if (id == R.id.nav_share) {        } else if (id == R.id.nav_send) {        }        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);        drawer.closeDrawer(GravityCompat.START);        return true;    }    //注册按钮响应事件    public void SetListener()    {        //定义控件变量        final  EditText register_account = (EditText) findViewById(R.id.register_account);        final  EditText register_password1 = (EditText) findViewById(R.id.register_password1);        final  EditText register_password2 = (EditText) findViewById(R.id.register_password2);        final  TextView register_warm1     = (TextView) findViewById(R.id.register_warm1);        final TextView register_warm2     = (TextView) findViewById(R.id.register_warm2);        final TextView register_warm3     = (TextView) findViewById(R.id.register_warm3);        //设置按钮点击监听        Button   register_bt        = (Button) findViewById(R.id.register_bt);        TextWatcher textWatcher1 = new TextWatcher() {            public void onTextChanged(CharSequence s, int start, int before,                                      int count) {            }            public void beforeTextChanged(CharSequence s, int start, int count,                                          int after) {            }            public void afterTextChanged(Editable s) {                String register_account_text = register_account.getText().toString();                if(s.length()<6||s.length()>10)                {                    register_warm1.setText("请将账号长度控制在6-10位之间");                }                else                    register_warm1.setText("");            }        };        register_account.addTextChangedListener(textWatcher1);        TextWatcher textWatcher2 = new TextWatcher() {            public void onTextChanged(CharSequence s, int start, int before,                                      int count) {            }            public void beforeTextChanged(CharSequence s, int start, int count,                                          int after) {            }            public void afterTextChanged(Editable s) {                String register_password1_text = register_password1.getText().toString();                String register_password2_text = register_password2.getText().toString();                if(register_password1_text.length()<6||register_password1_text.length()>10)                {                    register_warm2.setText("请将密码长度控制在6-10位之间");                }                else                    register_warm2.setText("");                if(!register_password2_text.equals(register_password1_text))                    register_warm3.setText("请输入一样的密码");                else                    register_warm3.setText("");            }        };        register_password1.addTextChangedListener(textWatcher2);        TextWatcher textWatcher3 = new TextWatcher() {            public void onTextChanged(CharSequence s, int start, int before,                                      int count) {            }            public void beforeTextChanged(CharSequence s, int start, int count,                                          int after) {            }            public void afterTextChanged(Editable s) {                String register_password2_text = register_password2.getText().toString();                String register_password1_text = register_password1.getText().toString();                if(!register_password2_text.equals(register_password1_text))                {                    register_warm3.setText("请输入一样的密码");                }                else                    register_warm3.setText("");            }        };        register_password2.addTextChangedListener(textWatcher3);        Button   reister_bt        = (Button) findViewById(R.id.register_bt);        reister_bt.setOnClickListener(new View.OnClickListener()        {            @Override            public void onClick(View view) {                String register_password1_text = register_password1.getText().toString();                String register_password2_text = register_password2.getText().toString();                String register_account_text = register_account.getText().toString();                String register_warm1_text = register_warm1.getText().toString();                String register_warm2_text = register_warm2.getText().toString();                String register_warm3_text = register_warm3.getText().toString();                if ( register_password1_text.equals("")||register_password2_text.equals("")||register_account_text.equals("") )                    Toast.makeText( getApplicationContext(),"请输入完整注册信息",Toast.LENGTH_SHORT).show();                else if (!register_warm1_text.equals("")||!register_warm2_text.equals("")||!register_warm3_text.equals(""))                    Toast.makeText( getApplicationContext(),"请输入正确的注册信息",Toast.LENGTH_SHORT).show();                else                {                    Toast.makeText(getApplicationContext(),"flag",Toast.LENGTH_LONG);                    ExecutorService exec = Executors.newCachedThreadPool();                    MyTask task = new MyTask();                    Future<Boolean> future = exec.submit(task);                    try {                        future.get(1, TimeUnit.SECONDS);                    } catch (InterruptedException e) {                        Toast.makeText(getApplicationContext(),"请求超时,请检查网络",Toast.LENGTH_LONG).show();                    } catch (ExecutionException e) {                        Toast.makeText(getApplicationContext(),"请求超时,请检查网络",Toast.LENGTH_LONG).show();                    } catch (TimeoutException e) {                        Toast.makeText(getApplicationContext(),"请求超时,请检查网络",Toast.LENGTH_LONG).show();                    }                    finally {                        exec.shutdownNow();                    }                }            }        });    }    //继承了callable接口    class MyTask implements Callable<Boolean> {        String flag="0";        @Override        public Boolean call() throws Exception {            try            {                getMainLooper().prepare();                EditText register_account = (EditText) findViewById(R.id.register_account);                EditText register_password1 = (EditText) findViewById(R.id.register_password1);                EditText register_password2 = (EditText) findViewById(R.id.register_password2);                String account =  register_account.getText().toString();                String password =  register_password1.getText().toString();                Socket socket = new Socket("10.0.2.2", 2333);                OutputStream outputStream = socket.getOutputStream();                String jsonStr = "{\"account\": \""+ account +"\"," + " \"password\": \""+password+"\"}";                BufferedWriter BW = new BufferedWriter(new OutputStreamWriter(outputStream));                BW.write(jsonStr);                BW.flush();                InputStream is=socket.getInputStream();                BufferedReader br=new BufferedReader(new InputStreamReader(is));                int data  =br.read();                System.out.println(data);                if(data==49)                    Toast.makeText(getApplicationContext(),"注册成功",Toast.LENGTH_LONG).show();                else                    Toast.makeText(getApplicationContext(),"已存在同名账户,请更换账户名",Toast.LENGTH_LONG).show();                socket.close();                flag="1";                getMainLooper().loop();            }            catch (java.net.SocketTimeoutException e)            {                Toast.makeText(getApplicationContext(),"连接失败,请检查网络",Toast.LENGTH_LONG).show();            }            catch (IOException e) {                Toast.makeText(getApplicationContext(), "连接失败,请检查网络", Toast.LENGTH_LONG).show();                e.printStackTrace();            }            return true;        }    }}

这是最终的修改过后的服务器端代码

#coding:utf-8import MySQLdb ,socket,threading ,time,jsonfrom json import *class myThread (threading.Thread):    def __init__(self):        threading.Thread.__init__(self)    #线程的主体代码    def run(self):        print "Starting " + self.name        try:            data=conn.recv(1024)   #接受数据            dict = eval(data)     #强转为dict            account=dict['account']            password = dict['password']            tuple = (account,password)            sql = " INSERT INTO users (account,password) VALUES(%s,%s)";            threadLock.acquire()    #获取线程锁            #接下来执行数据库操作            cur=conne.cursor()            cur.execute(sql,tuple)            #执行完毕后向客户端发1表示成功            conn.send("1")            print("succeed in writing")        except Exception,ex:            conn.send("0")            print("failed in writing")        finally:            cur.close()            threadLock.release()            conn.close()#连接数据库conne=MySQLdb.connect(host='127.0.0.1',user='root',passwd='ONS2015',db='test',port=3306)threadLock = threading.Lock()HOST='127.0.0.1'PORT=2333#创建sockets= socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.bind(('127.0.0.1',2333))#设置最高同时监听数s.listen(1000)while (1):    conn,addr = s.accept()    # 接受客户端端的连接后,就开启一个线程处理客户端的数据    thread = myThread()    thread.start()

这是最终效果图:
1.未填完整信息
未填完整信息

2.输入信息不正确
输入信息不正确

3.网络连接超时
网络连接超时

4存在相同用户名.
存在相同用户名

5,注册成功
注册成功

0 0