- [SQLSERVER] Loại bỏ Restricted User trên database MSSQL
- [C#] Hướng dẫn tạo mã QRcode Style trên winform
- [C#] Hướng dẫn sử dụng temp mail service api trên winform
- [C#] Hướng dẫn tạo mã thanh toán VietQR Pay không sử dụng API trên winform
- [C#] Hướng Dẫn Tạo Windows Service Đơn Giản Bằng Topshelf
- [C#] Chia sẻ source code đọc dữ liệu từ Google Sheet trên winform
- [C#] Chia sẻ source code tạo mã QR MOMO đa năng Winform
- [C#] Chia sẻ source code phần mềm lên lịch tự động chạy ứng dụng Scheduler Task Winform
- [Phần mềm] Tải và cài đặt phần mềm Sublime Text 4180 full version
- [C#] Hướng dẫn download file từ Minio Server Winform
- [C#] Hướng dẫn đăng nhập zalo login sử dụng API v4 trên winform
- [SOFTWARE] Phần mềm gởi tin nhắn Zalo Marketing Pro giá rẻ mềm nhất thị trường
- [C#] Việt hóa Text Button trên MessageBox Dialog Winform
- [DEVEXPRESS] Chia sẻ code các tạo report in nhiều hóa đơn trên XtraReport C#
- [POWER AUTOMATE] Hướng dẫn gởi tin nhắn zalo từ file Excel - No code
- [C#] Chia sẻ code lock và unlock user trong domain Window
- [DEVEXPRESS] Vẽ Biểu Đồ Stock Chứng Khoán - Công Cụ Thiết Yếu Cho Nhà Đầu Tư trên Winform
- [C#] Hướng dẫn bảo mật ứng dụng 2FA (Multi-factor Authentication) trên Winform
- [C#] Hướng dẫn convert HTML code sang PDF File trên NetCore 7 Winform
- [C#] Hướng dẫn viết ứng dụng chat với Gemini AI Google Winform
Lập trình android - Ứng dụng giao tiếp với SQL Server
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.
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 ^^!