1. 程式人生 > >android與java web互動完成簡單的登入和註冊

android與java web互動完成簡單的登入和註冊

   本文的知識點包括android客戶端的網路程式設計、訊息機制、IO流、多執行緒和java web伺服器端的servlet、資料庫操作、javabean技術、工具類和測試類的使用。

客戶端

執行效果圖


佈局檔案

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.ningxiaojian.clientlogindemo.MainActivity">

    <EditText
        android:id="@+id/et_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入登入賬號"/>

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入登入密碼"/>

    <Button
        android:id="@+id/bt_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登入"
        android:onClick="login"/>

    <Button
        android:id="@+id/bt_register"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="註冊"
        android:onClick="register"/>


</LinearLayout>
程式主入口
MainActivity

package com.ningxiaojian.clientlogindemo;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

public class MainActivity extends AppCompatActivity {

    private EditText username;
    private EditText password;
    private String usernameStr;
    private String passwordStr;
    private final int LOGINSUCCESS=0;
    private final int LOGINNOTFOUND=1;
    private final int LOGINEXCEPT=2;
    private final int REGISTERSUCCESS=3;
    private final int REGISTERNOTFOUND=4;
    private final int REGISTEREXCEPT=5;

    @SuppressLint("HandlerLeak")
    Handler handler=new Handler(){//訊息機制,用來在子執行緒中更新UI
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){//具體訊息,具體顯示
                case LOGINSUCCESS:
                    Toast.makeText(getApplicationContext(),(String)msg.obj,Toast.LENGTH_LONG).show();
                    break;
                case LOGINNOTFOUND:
                    Toast.makeText(getApplicationContext(),(String)msg.obj,Toast.LENGTH_LONG).show();
                    break;
                case LOGINEXCEPT:
                    Toast.makeText(getApplicationContext(),(String)msg.obj,Toast.LENGTH_LONG).show();
                    break;
                case REGISTERSUCCESS:
                    Toast.makeText(getApplicationContext(),(String)msg.obj,Toast.LENGTH_LONG).show();
                    break;
                case REGISTERNOTFOUND:
                    Toast.makeText(getApplicationContext(),(String)msg.obj,Toast.LENGTH_LONG).show();
                    break;
                case REGISTEREXCEPT:
                    Toast.makeText(getApplicationContext(),(String)msg.obj,Toast.LENGTH_LONG).show();
                    break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //找到我們需要的控制元件
        username = (EditText) findViewById(R.id.et_username);
        password = (EditText) findViewById(R.id.et_password);


    }
    //登入按鈕的點選事件,也可以用set監聽器的方法,不過這種方法簡單
    public void login(View v){
        //獲取編輯框內的內容
        usernameStr = username.getText().toString().trim();
        passwordStr = password.getText().toString().trim();

        //判斷是否輸入為空(在這裡就不再進行正則表示式判斷了)
        if(usernameStr.equals("") || passwordStr.equals("")){
            Toast.makeText(MainActivity.this,"使用者名稱或密碼不能為空",Toast.LENGTH_SHORT).show();
        }//進行登入操作(聯網操作要新增許可權)
        else {
            //聯網操作要開子執行緒,在主執行緒不能更新UI
            new Thread(){

                private HttpURLConnection connection;


                @Override
                public void run() {

                    try {
                        //封裝成傳輸資料的鍵值對,無論get還是post,傳輸中文時都要進行url編碼(RULEncoder)
                        // 如果是在瀏覽器端的話,它會自動進行幫我們轉碼,不用我們進行手動設定
                        String data2= "username="+ URLEncoder.encode(usernameStr,"utf-8")+"&password="+ URLEncoder.encode(passwordStr,"utf-8")+"&sign="+URLEncoder.encode("1","utf-8");
                        connection=HttpConnectionUtils.getConnection(data2);
                        int code = connection.getResponseCode();
                        if(code==200){
                            InputStream inputStream = connection.getInputStream();
                            String str = StreamChangeStrUtils.toChange(inputStream);//寫個工具類流轉換成字串
                            Message message = Message.obtain();//更新UI就要向訊息機制傳送訊息
                            message.what=LOGINSUCCESS;//用來標誌是哪個訊息
                            message.obj=str;//訊息主體
                            handler.sendMessage(message);

                        }
                        else {
                            Message message = Message.obtain();
                            message.what=LOGINNOTFOUND;
                            message.obj="註冊異常...請稍後再試";
                            handler.sendMessage(message);
                        }
                    } catch (Exception e) {//會丟擲很多個異常,這裡抓一個大的異常
                        e.printStackTrace();
                        Message message = Message.obtain();
                        message.what=LOGINEXCEPT;
                        message.obj="伺服器異常...請稍後再試";
                        handler.sendMessage(message);
                    }
                }
            }.start();//不要忘記開執行緒
        }
    }
    //註冊按鈕的點選事件
    public void register(View v){
        usernameStr = username.getText().toString().trim();
        passwordStr = password.getText().toString().trim();
        if(usernameStr.equals("") || passwordStr.equals("")){
            Toast.makeText(MainActivity.this,"使用者名稱或密碼不能為空",Toast.LENGTH_SHORT).show();
        }
        else {
                new Thread(){

                    HttpURLConnection connection=null;
                    @Override
                    public void run() {
                        try {
                            String data= "username="+ URLEncoder.encode(usernameStr,"utf-8")+"&password="+ URLEncoder.encode(passwordStr,"utf-8")+"&sign="+URLEncoder.encode("2","utf-8");
                            connection=HttpConnectionUtils.getConnection(data);
                            int code = connection.getResponseCode();
                            if(code==200){
                                InputStream inputStream = connection.getInputStream();
                                String str = StreamChangeStrUtils.toChange(inputStream);
                                Message message = Message.obtain();
                                message.obj=str;
                                message.what=REGISTERSUCCESS;
                                handler.sendMessage(message);
                            }
                            else {
                                Message message = Message.obtain();
                                message.what=REGISTERNOTFOUND;
                                message.obj="註冊異常...請稍後再試";
                                handler.sendMessage(message);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            Message message = Message.obtain();
                            message.what=REGISTEREXCEPT;
                            message.obj="伺服器異常...請稍後再試";
                            handler.sendMessage(message);
                        }

                    }
                }.start();//不要忘記開執行緒

        }
    }
}

流轉換成字串的工具類
StreamChangeStrUtils
package com.ningxiaojian.clientlogindemo;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 流轉換成字串的工具類
 */

public class StreamChangeStrUtils {
    public static String toChange(InputStream inputStream) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();//陣列流,在流的內部有個緩衝區,可以進行轉換成位元組
        //下面是屬於io流的知識,在此不再贅述
        byte b[]=new byte[1024];
        int len=-1;
        while ((len=inputStream.read(b))!=-1){
            bos.write(b,0,len);
        }
        inputStream.close();//關閉流,陣列流會自動關閉,關閉是否都可以
        String str = new String(bos.toByteArray());
        //伺服器預設返回的是gbk,如果要在android端解決亂碼,可以在此設定為gbk,一般提倡的是伺服器解決
        // 讓伺服器給我們返回utf-8,因為在android本地預設的是utf-8
        return str;
    }
}

   聯網工具類

HttpConnectionUtils

package com.ningxiaojian.clientlogindemo;

import android.os.Message;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;

/**
 * 獲取聯網連線
 * Created by Justin on 2018/4/16.
 */

public class HttpConnectionUtils {
    public static HttpURLConnection getConnection(String data) throws Exception {

            //通過URL物件獲取聯網物件
            URL url= new URL("http://192.168.1.104:8080/AndroidLoginDemo/LoginServlet");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");//設定post請求
            connection.setReadTimeout(5000);//設定5s的響應時間
            connection.setDoOutput(true);//允許輸出
            connection.setDoInput(true);//允許輸入
            //設定請求頭,以鍵值對的方式傳輸(以下這兩點在GET請求中不用設定)
            connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded ");
            connection.setRequestProperty("Content-Length",data.length()+"");//設定請求體的長度
            OutputStream outputStream = connection.getOutputStream();
            outputStream.write(data.getBytes());//進行傳輸操作
            //判斷服務端返回的響應碼,這裡是http協議的內容
            return connection;
    }
}
   聯網操作一定要在
AndroidManifest.xml加上許可權
<uses-permission android:name="android.permission.INTERNET"/>

伺服器端(Tomcat)

首先去mysql建立一個數據庫,表結構如下
因為使用到mysql,所以要把jdbc的驅動類新增到webcontent->web-inf->lib中
mysql-connector-java-5.1.45-bin.jar

在eclipse建立以下包名

com.ningxiaojian.dao:dao層介面
com.ningxiaojian.dao.impl:dao層介面的實現
com.ningxiaojian.domain:javabean物件
com.ningxiaojian.service:邏輯層的介面
com.ningxiaojian.service.impl:邏輯層的實現
com.ningxiaojian.web.control:存放servlet
com.ningxiaojian.utils:存放工具類
com.ninxiaojian.test:存放測試類

建立java物件
User.java
package com.ningxiaojian.domain;

/**
 *
 *設定一個javabean物件,用來封裝dao層取出的資料
 * @author Justin
 *
 */
public class User {
	private String username;
	private String password;
	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;
	}
	
}

dao層介面
UserDao.java
package com.ningxiaojian.dao;

import java.util.List;

import com.ningxiaojian.domain.User;

public interface UserDao {
	//找到所有元素,用來驗證登入資訊
	public  List<User> findAll();
	//插入元素,用來註冊
	public void insertElement(User people);
	
}
dao層實現類
UserDaoImpl.java
package com.ningxiaojian.dao.impl;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.ningxiaojian.dao.UserDao;
import com.ningxiaojian.domain.User;
import com.ningxiaojian.utils.JDBCUtils;

public class UserDaoImpl implements UserDao {

	Connection connection=null;
	PreparedStatement ps=null;
	ResultSet rs=null;
	
	/**
	 * dao層,從資料庫裡面取出資料
	 */
	@Override
	public List<User> findAll() {
		List<User> list=null;
		try {
			//通過工具類獲得連線
			connection = JDBCUtils.getConnetion();
			//通過連線物件獲取操作資料庫的物件
			String sql="SELECT * FROM user;";//查詢sql語句
			ps=connection.prepareStatement(sql);
			//返回查詢結果集
			rs=ps.executeQuery();
			//遍歷rs,並封裝資料
			list=new ArrayList<User>();
			while(rs.next()) {
				User user=new User();
				user.setUsername(rs.getString(2));//索引從1開始,id引數不用取
				user.setPassword(rs.getString(3));
				list.add(user);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		finally{
			JDBCUtils.close(connection, ps, rs);//關閉連線
			
		}
		return list;
	}

	@Override
	public void insertElement(User people) {
		try {
			connection=JDBCUtils.getConnetion();
			String sql="INSERT INTO user(username,password) VALUES(?,?);";//插入語句
			ps=connection.prepareStatement(sql);
			ps.setString(1,people.getUsername());//使用prepareStatement可以防止sql注入
			ps.setString(2,people.getPassword());
			//執行更新語句
			ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			JDBCUtils.close(connection, ps, rs);
		}
	}

}

jdbc工具類
JDBCUtils.java

package com.ningxiaojian.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;



/**
 * 因為要多次用到以下的步驟,所以寫一個工具類來操作jdbc
 * @author Justin
 *在這裡不要導錯包,import com.mysql.jdbc.PreparedStatement;是錯的
 */
public class JDBCUtils {
	/**
	 * 獲得jdbc連線
	 */
	static Connection connection=null;
	public static Connection getConnetion() throws Exception {
		//載入jdbc驅動
		Class.forName("com.mysql.jdbc.Driver");
		//建立連線資料庫的路徑
		String url = "jdbc:mysql://localhost/android_login?user=root&password=12345";
		//通過url獲得與資料庫的連線
		connection = DriverManager.getConnection(url);
		return connection;
	}
	
	public static void close(Connection connection,PreparedStatement ps,ResultSet rs) {
		//一定要確保關閉連線,以下關閉步驟是參照官方文件的,有權威性
		if(rs!=null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(ps!=null) {
			try {
				ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(connection!=null) {
			try {
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

測試dao層方法的test類(僅作測試作用)
TestDao.java
package com.ninxiaojian.test;

import java.util.List;

import org.junit.jupiter.api.Test;

import com.ningxiaojian.dao.UserDao;
import com.ningxiaojian.dao.impl.UserDaoImpl;
import com.ningxiaojian.domain.User;

class TestDao {

	/**
	 * 測試類,測試dao層那兩個方法是否查詢和插入正確
	 */
	@Test
	void testFindAll() {
		UserDao dao=new UserDaoImpl();
		List<User> list = dao.findAll();
		for(int i=0;i<list.size();i++) {//遍歷list
			User user=list.get(i);
			System.out.println("username:"+user.getUsername());
			System.out.println("password:"+user.getPassword());
		}
	}
	@Test
	void testInsertElement() {
		UserDao dao=new UserDaoImpl();
		User people=new User();
		people.setUsername("hhhhh");
		people.setPassword("66666");
		dao.insertElement(people);
	}

}

servlet類
LoginServlet.java
package com.ningxiaojian.web.control;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ningxiaojian.domain.User;
import com.ningxiaojian.service.UserService;
import com.ningxiaojian.service.impl.UserServiceImpl;


@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
   
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");//解決請求亂碼(post)
		response.setCharacterEncoding("UTF-8");//解決響應亂碼,下面要以字元流輸出(若位元組流輸出則要再次編碼)
		String username=request.getParameter("username");
		String password=request.getParameter("password");
		String sign=request.getParameter("sign");
		PrintWriter out=response.getWriter();
		//把傳來的資料封裝進javabean中
		User user=new User();
		user.setUsername(username);
		user.setPassword(password);
		UserService service=new UserServiceImpl();
		if("1".equals(sign)) {//登入操作(設定了一個標記)
			String loginInfo=service.checkLogin(user);
			out.print(loginInfo);
		}
		else if("2".equals(sign)) {//註冊操作
			String registerInfo=service.register(user);
			out.print(registerInfo);
		}
		
		System.out.println(username);//在控制檯輸出
		System.out.println(password);
		System.out.println(sign);
		
	
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

service介面層
UserService.java
package com.ningxiaojian.service;

import com.ningxiaojian.domain.User;

public interface UserService {
	//查驗登入
	public String checkLogin(User user);
	//註冊使用者
	public String register(User user);
}

service實現層,服務端的主要邏輯
UserServiceImpl.java
package com.ningxiaojian.service.impl;

import java.util.List;

import com.ningxiaojian.dao.UserDao;
import com.ningxiaojian.dao.impl.UserDaoImpl;
import com.ningxiaojian.domain.User;
import com.ningxiaojian.service.UserService;

public class UserServiceImpl implements UserService {

	UserDao dao=new UserDaoImpl();
	
	/*
	 * 主要的邏輯實現
	 */
	@Override
	public String checkLogin(User user) {
		List<User> list = dao.findAll();
		for(int i=0;i<list.size();i++) {//遍歷集合
			User user2=list.get(i);
			if(user2.getUsername().equals(user.getUsername()) && user2.getPassword().equals(user.getPassword())) {
				return "登入成功";
			}
		}
		return "登入失敗,密碼輸入錯誤";
	}

	@Override
	public String register(User user) {
		List<User> list = dao.findAll();
		for(int i=0;i<list.size();i++) {
			User user2=list.get(i);
			if(user2.getUsername().equals(user.getUsername())) {
				return "註冊失敗,該使用者名稱已存在!";
			}
		}
		dao.insertElement(user);
		return "註冊成功";
	}

}

以上就是全部的程式碼,每句程式碼都會有詳細的解釋