NEWS

Lập trình android - Ứng dụng giao tiếp với SQL Server

Lập trình android - Ứng dụng giao tiếp với SQL Server
Đăng bởi: TONA Cody - Lượt xem: 30472 22:31:51, 04/01/2018C#   In bài viết

Android app không thể giao tiếp một cách trực tiếp với SQL Server, bởi đơn giản là do SQL Server thuộc về Microsoft còn Android là con cưng của Google, hai gã khổng lồ về công nghệ của thế giới. May mắn thay, chúng ta có thể viết một ứng dụng bằng Java, mà Java có lại hỗ trợ kỹ thuật cho phép người dùng có thể sử dụng ứng dụng Android để thao tác với cơ sở dữ liệu trên SQL Server. Để làm được điều này, lập trình viên phải add thư viên jTDS vào ứng dụng Android của mình.

Các bạn có thể download ứng mọi phiên bản của jTDS tại đây.

Android application connect to SQL Server

Bài viết dựa trên những kinh nghiệm cá nhân, không thể tránh khỏi sai sót, và mục tiêu là hổ trợ những bạn mới làm quen với lập trình Android. Ý kiến đóng góp, xin vui lòng để lại dưới mục bình luạn. ^^

Để làm được bài này, các bạn cần có ít nhiều hiểu cơ bản về Activity, chuyển đổi giữa các Activity, khái niệm về Intent trong Android. Đồng thời, tui cũng ứng dụng luôn xử lý đa tiến trình với AsyncTask mặc dù yêu cầu truy vấn chỉ là một bản ghi nhưng mà luyên tập cho nó nhuyễn vì trước sau cũng phải xài anh này nhiều mà ^^.

Ứng dụng Android thao tác với cơ sở dữ liệu SQL Server

Bắt đầu với khởi tạo một ứng dụng Android trên Android Studio, bao gồm 2 Activity dùng để chuyển đổi giữa 2 màn hình ứng dụng. File class HASH dùng để băm chuỗi mật khẩu, SERVER chưa thông tin kết nối SQL Server và 2 class Activity dùng để xử lý trên giao diện ứng dụng Android.

ANDROID-connect-to-sql-server-ket-noi-sql-server-trong-android-2

 

Các file java:

SERVER.java

 

HASH.java

package com.example.erp_tuyen.loginsql;

/**
 * Created by Erp-Tuyen on 03/01/2018.
 */

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by Erp-Tuyen on 02/01/2018.
 */

public class HASH {

    public static final String md5(final String s) {
        final String md5 = "MD5";
        try {
            // Create MD5 Hash
            MessageDigest digest = java.security.MessageDigest
                    .getInstance(md5);
            digest.update(s.getBytes());
            byte messageDigest[] = digest.digest();

            // Create Hex String
            StringBuilder hexString = new StringBuilder();
            for (byte aMessageDigest : messageDigest) {
                String h = Integer.toHexString(0xFF & aMessageDigest);
                while (h.length() < 2)
                    h = "0" + h;
                hexString.append(h);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

}

UserActivity.java

package com.example.erp_tuyen.loginsql;

import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class UserActivity extends Activity {

    EditText edtOldPw, edtNewPw, edtReNewPw;
    TextView tvUser,tvTitleUs;
    Button btnSubmit;
    ProgressBar progressBar;

    String un,pw,hoten;
    Boolean isUpdated;

    String z;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);

        edtOldPw=(EditText)this.findViewById(R.id.edtOldPw);
        edtNewPw=(EditText)this.findViewById(R.id.edtNewPw);
        edtReNewPw=(EditText)this.findViewById(R.id.edtReNewPw);
        btnSubmit=(Button)this.findViewById(R.id.btnSubmit);
        tvUser=(TextView)this.findViewById(R.id.tvUser);
        tvTitleUs=(TextView)this.findViewById(R.id.tvTitleUs);
        progressBar=(ProgressBar)this.findViewById(R.id.progressBar);

        progressBar.setVisibility(View.GONE);

        Bundle extras=getIntent().getExtras(); //dùng cái này để hứng gói tin hồi nãy.
        un=extras.getString("USERNAME","N/A");//lấy giá trị của cái key là USERNAME
        pw=extras.getString("PASSWORD","N/A");// như trên
        hoten=extras.getString("HOTEN","N/A");// vẫn rứa

        tvUser.setText(hoten);

        btnSubmit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                DoUpdate up= new DoUpdate();
                up.execute("");//dùng gọi... ak mà nói trong bài trước rồi
            }
        });
    }

    void finishUpdate(){ //tạo gói Intent để gửi trả cho cái thằng kia nãy nó gửi và nó đang đợi trả
        if(isUpdated){
            Intent intent= new Intent(this,MainActivity.class); //bắn lại cho thằng MainActivity.class
            intent.putExtra("PASSWORD",pw);
            this.setResult(RESULT_OK,intent);
            super.finish(); //k có cái này thì nó k gửi trả, nghĩa là bên kia sẽ nghĩ là chưa có gửi tới
        }
    }

    public class DoUpdate extends AsyncTask {
        @Override
            protected String doInBackground(String... strings) {

            String oPw,nPw,rnPw;
            oPw=edtOldPw.getText().toString();
            nPw=edtNewPw.getText().toString();
            rnPw=edtReNewPw.getText().toString();

            isUpdated=false;
            if(oPw.trim().equals("")||nPw.trim().equals("")||rnPw.trim().equals("")){
                z="Vui lòng nhập đủ thông tin";
            }else if(!oPw.equals(pw)){
                z="Mật khẩu cũ không đúng !";
            }else if(!nPw.equals(rnPw) ){
                z="Mật khẩu không trùng khớp !";
            }
            else if(pw.equals(rnPw) ){
                z="Mật khẩu mới phải khác với mật khẩu cũ !";
            } else {
                try {
                    Connection conn = SERVER.Connect();
                    if (conn != null) {
                        int resultSet;
                        String query = "Update tbl_user set matkhau='" + HASH.md5(rnPw)  + "' where  matkhau='" + HASH.md5(pw) + "' and tendangnhap='"+un+"'";
                        Statement stmt = conn.createStatement();
                        resultSet= stmt.executeUpdate(query);//thực thi lệnh, trả về số dòng thực hiện dc

                        if(resultSet==1)
                        {
                            z="Mật khẩu đã được thay đổi ! ";
                            pw=rnPw;
                            isUpdated=true;//lại đánh dấu chủ quyền
                            conn.close();
                        }
                        else
                        {
                            z="Không thể hoàn tất thay đổi mật khẩu ! ";
                        }
                    } else {
                        z="Cập nhật không thành công ! Lỗi kết nối !";
                    }
                } catch (Exception ex)
                {
                    Log.e("ERUs", ex.getMessage());
                }
            }
            return z;
        }


        @Override
        protected void onPreExecute() {
            progressBar.setVisibility(View.VISIBLE);
            // TODO Auto-generated method stub
            super.onPreExecute();
        }

        @Override
        protected void onProgressUpdate(String... values) {
            //super.onProgressUpdate(values);
            //Cập nhật thông tin như thay đổi giá trị progressBar ở đây !
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            Toast.makeText(UserActivity.this, s, Toast.LENGTH_LONG).show();
            progressBar.setVisibility(View.GONE);
            finishUpdate();//gọi hàm trả lui gói Intent
        }
    }

}

Và MainActivity.java

package com.example.erp_tuyen.loginsql;

import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class MainActivity extends Activity {

    EditText edtUserName, edtPaddword;
    Button btnLogin;
    ProgressBar pgbLoading;
    TextView tvResult;
    ResultSet resultSet;

      final int CHAN_PW_CODE=4; //Code dùng để gửi gói Intent qua Activity_User

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnLogin=(Button)this.findViewById(R.id.btnLogin);
        edtUserName=(EditText)this.findViewById(R.id.edtUserName);
        edtPaddword=(EditText)this.findViewById(R.id.edtPassword);
        pgbLoading=(ProgressBar)this.findViewById(R.id.pgbLoading);
        tvResult=(TextView)this.findViewById(R.id.tvResult);

        pgbLoading.setVisibility(View.GONE);

        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                DoLogin  doLogin = new DoLogin();
                doLogin.execute("");//Thực thi doLogin.doInBackground();
            }
        });
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {//Hàm này sẽ xử lý nếu khi mình gửi Intent là startActivityForResult, nhấn F8, bỏ qua cái này, xem xuống dưới trước
        if (requestCode == CHAN_PW_CODE) { //Kiểm tra xem code trả về có đúng ban đầu không này không
            // Phài chắc chắn là thành công mới gửi
            if (resultCode == RESULT_OK) {
                String rs=data.getStringExtra("PASSWORD");
                Toast.makeText(this,"Mật khẩu đã đổi thành "+ rs ,Toast.LENGTH_LONG).show();
                edtPaddword.setText(rs);
                btnLogin.setVisibility(View.VISIBLE);
            }
        }
    }

    //---------------------------------------------------------------------------------------------
    public class DoLogin extends AsyncTask
    {

        String z = ""; //cái này dùng để hứng kết quả khi chạy hàm truy vấn tới SQL Server
        String hoten=""; //Cái này sẽ chứa họ tên đầy đủ khi truy vấn được
        Boolean isSuccess = false; //Biến nhận biết là có truy vấn thành công hay không

        String userid = edtUserName.getText().toString(); // biến cục bộ, xài cục bộ
        String password = edtPaddword.getText().toString(); // như trên


        @Override
        protected void onPreExecute() {
            pgbLoading.setVisibility(View.VISIBLE); // bật cái con chạy lên
            btnLogin.setVisibility(View.GONE);//Ẩn button đi
        }

        @Override
        protected String doInBackground(String... params) {
        try {
                Connection con = SERVER.Connect(); //khởi tạo kết nối tới server, SERVER chính là class riêng, tìm trong table java
                if (con == null) {
                    z = "Không thể kết nối với Server"; //Tiếng Việt :D
                } else {
                String query = "select * from view_user where tendangnhap='" + userid + "' and matkhau='" + HASH.md5(password) + "'";
                //trên đây là câu truy vấn
                    Statement stmt = con.createStatement(); //blah blah blah
                    resultSet = stmt.executeQuery(query); //thực thi và trả về một cục ResultSet, nó là gì thì Google, tui chịu

                    //ResultSet rs = SERVER.executeQuery(query);
                    if(resultSet.next())//nếu trong resultset không null thì sẽ trả về True
                    {
                        hoten=resultSet.getString("hoten");//Hàm lấy giá trị của tên cột (trường: field name) truyền vào
                        z = "Hi, " + hoten; //Hey, i'm TONA
                        //tvResult.setText(hoten);
                        isSuccess=true; //Oánh dấu chủ quyền, làm dấu thôi, để biết là hàm nó chạy tới đây, xíu mình dùng biến này kiểm tra coi thử chạy tới đây hay không đó mà, chạy tới đây nghĩa là thành công rồi đó.
                        con.close();//Đấm vỡ mồm SERVER xong thì phải băng bó cho nó.
                    }
                    else
                    {
                        z = "Tài khoản không tồn tại !";//Lại Tiếng Việt
                        isSuccess = false; //Chạy tới đây là hỏng rồi
                    }
                }
            }
            catch (Exception ex)
            {
                isSuccess = false;
                z = "Lỗi !";
            }
            return z;//Trả về, thứ này chính là cái doInBackground(String... params), nó buộc mình phải trả về String, do tui khai báo là String thôi, nếu ban đầu khai kiểu khác thì nó sẽ bắt trả về kiểu khác, trong bài trước mình trả về null, vì mình chẳng cần bắt gì cả, chỉ chạy thôi.
        }

        @Override
        protected void onProgressUpdate(String... values) {
            //super.onProgressUpdate(values); //Thường dùng để thay đổi trạng thái tiến trình đang làm tới % blah blah, tui k xài
        }

        @Override
        protected void onPostExecute(String r) {// sau khi tiến trình kết thúc thì sẽ gọi tới hàm này
            pgbLoading.setVisibility(View.GONE);//Tắt cái cục xoay xoay đi
            Toast.makeText(MainActivity.this,r,Toast.LENGTH_SHORT).show(); // cái r chính là cái mà nó lấy từ cái hàm doInBackground(String... params), hàm này return z (String), nó sẽ quăng qua hàm này để thực hiện cái bên trong
            if(isSuccess) {//kiểm tra chủ quyền của mình có tới vị trí đánh dấu nãy không :D
                Toast.makeText(MainActivity.this,r,Toast.LENGTH_SHORT).show();

                Intent intent= new Intent(MainActivity.this, UserActivity.class);//tạo ra một "gói" Intent gửi từ this đến UserActivity.class
                //setContentView(android.view.View);
                intent.putExtra("USERNAME",userid);//nhét cái userid vô intent và đặt khóa là USERNAME
                intent.putExtra("PASSWORD",password);//như trên
                intent.putExtra("HOTEN",hoten);//như rứa
                startActivityForResult(intent,CHAN_PW_CODE);//gửi đi, có đợi trả về, nếu trả về sẽ chạy cái hồi nãy nhấn F8
                //startActivity(intent); kiểu này sẽ không đợi trả về
                //intent
            }
        }
    }

}

Như vậy là hoàn tất ứng dụng, và có thể chạy thử được rồi.

Tuy nhiên có một vài lưu ý sau:

  • Thư viện này chỉ thấy được SQL Server có Instance là mặc định của máy. Nhiều bạn cài SQL Server với Instance dạng COMPUTER_NAMEINSTANCE_NAME thì nó sẽ báo là không tìm thấy được Server.
  • Chỉ chấp nhận là IP Server. Ví dụ Instance mặc định của mình là TONA, nhưng IP máy mình là 172.20.10.2 thì bắt buộc mình phải để là IP 172.20.10.2. IP này phải đăng nhập  được vào SQL Server nhé.
  • Hãy tắt tường lửa nếu bạn test trên máy nhà.

 Đây là thành quả đạt được:

Download Full Source here

HAPPY CODING ^^!

 

THÔNG TIN TÁC GIẢ

BÀI VIẾT LIÊN QUAN

Lập trình android - Ứng dụng giao tiếp với SQL Server
Đăng bởi: TONA Cody - Lượt xem: 30472 22:31:51, 04/01/2018C#   In bài viết