Android登录客户端
PS:现在只实现了注册功能,但是登录功能是一个道理,看完注册应该都会。
项目地址在文末,只能用来试手,估计要改很多才能用在你的实际项目中。
1、首先搭建登录界面
代码如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.15"></RelativeLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.7"
android:orientation="vertical">
<com.example.activity.smartparking.CircleImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:layout_marginTop="130dp"
android:src="@drawable/swpu"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="18sp"
android:text="账号"/>
<EditText
android:id="@+id/account_r"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="请输入账号"
android:maxLength="10"
android:layout_gravity="center_vertical"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="18sp"
android:text="密码"/>
<EditText
android:id="@+id/password_r"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="请输入密码"
android:maxLength="10"
android:layout_gravity="center_vertical"
android:inputType="textPassword"/>
</LinearLayout>
<Button
android:layout_gravity="center"
android:background="@color/buttonLogin"
android:id="@+id/register_r"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="注册"/>
</LinearLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.15"></RelativeLayout>
</LinearLayout>
2、信息传输
搭建好了界面之后,就需要解决数据传输的问题。我们需要将输入的账号以及密码信息传输到服务器。
信息传输我们使用OKhttp,要使用OKhttp,我们需要导入:
implementation 'com.squareup.okhttp3:okhttp:3.2.0'
由于OKhttp还是比较底层的,我们还是将OKhttp进行简单的封装比较好用。这里我用了一个github别人封装好的库(忘了是哪个大哥的了,忏悔一下),源码在文末。
然后我们就可以进行数据传输了,我们在Register.Activity中操作。
import android.content.Intent;
import android.os.Looper;
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.Toast;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Response;
public class RegisterActivity extends AppCompatActivity implements View.OnClickListener {
private EditText account,password;
private Button register;
private String str1,str2;
private static String url = "http://10.99.22.247:80/SmartParking/reg1";
private Map<String,String> paramsMap = null;
private CallBackUtil callBackUtil = null;
private String jsonstr = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
init();
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.register_r:
str1 = account.getText().toString();
str2 = password.getText().toString();
//下面这就是OKhttp的操作了,首先在rgister_f中定义好我们需要东西,最后用别人封装好的一句OkhttpUtil.okHttpPostJson(url,jsonstr,callBackUtil)就可以发送OKhttp请求了。
register_f();
OkhttpUtil.okHttpPostJson(url,jsonstr,callBackUtil);
}
}
private void init() {
account = (EditText)findViewById(R.id.account_r);
password = (EditText)findViewById(R.id.password_r);
register = (Button)findViewById(R.id.register_r);
register.setOnClickListener(this);
}
private Object register_f() {
//我们装备传输的数据是Json格式的,json数据写的方法有几种,我是通过先写Map数组,在直接将数组转换为json数据。
paramsMap = new HashMap<String, String>();
paramsMap.put("uname",str1);
paramsMap.put("pwd",str2);
Gson gson = new Gson();
jsonstr = gson.toJson(paramsMap);
//callBackUtil是别人封装好的OKhttp库
callBackUtil = new CallBackUtil() {
@Override
public Object onParseResponse(Call call, Response response) throws IOException {
String resp = response.body().string();
if(resp.equals("success")){
Looper.prepare();
Toast.makeText(RegisterActivity.this, "注册成功,请登录", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(RegisterActivity.this,Login.class);
startActivity(intent);
Looper.loop();
return null;
}else if (resp.equals("failure")){
Looper.prepare();
Toast.makeText(RegisterActivity.this, "注册失败,请重新注册", Toast.LENGTH_SHORT).show();
Looper.loop();
return null;
}
return null;
}
@Override
public void onFailure(Call call, Exception e) {
Looper.prepare();
Toast.makeText(RegisterActivity.this, "注册失败", Toast.LENGTH_SHORT).show();
Looper.loop();
}
@Override
public void onResponse(Object response) {
}
};
return null;
}
}
3、服务器搭建
我是在本机用Tomcat服务器测试的,关于Tomcat服务器的测试,我就不在这里说了,网上教程很多。
在搭建好了Tomcat服务器之后,我们先提一个小东西,Eclipse的TCP/IP Monitor,这个东西是监听端口数据的,我们可以用它来监听Servlet的请求数据(request)和响应数据(response)。
TCP/IP Monitor打开方式:进入菜单 Window->Show View->Other,在弹出框中选择 TCP/IP Monitor 项。
空白处右键选择properties,点击 Add 添加一个新的监控。
⭐⭐设置各项属性,其中各属性含义如下:
-
Local monitoring port:本地的监控端口,此监控端口必须未被使用;且设置之后,客户端程序须修改为向此端口发送请求,而不是之前的服务器接收的端口;
-
Host name:服务器地址(这里是本机);
-
Port:服务器端口;
-
Type:HTTP/HTTPS,根据实际使用协议选择;
-
Timeout:monitor在尝试重连之前的等待时间。
简单来讲,假设你开始访问的地址是:http://10.99.22.247:8080/SmartParking/reg1, 现在你就需要将你之前设置的端口改为上面的Local monitoring port端口(第一个图的第一个输入),即改为http://10.99.22.247:80/SmartParking/reg1,TCP/IP Monitor会将发往端口80的数据转发给你实际用到的端口8080。
4、服务器处理请求(request)及返回(response)
写这个之前我想先说说服务起的相关知识,前文所提到的访问地址,如http://10.24.22.247:8080/SmartParking/reg1之类的信息具体指什么呢?
10.24.22.247 是你服务器的ip地址(这里提一句,如果你是在模拟器上运行的话,这里不能填localhost,需要你电脑在公网下面的私网ip(cmd输入ipconfig找到ipv4就是你的ip了,校园网的话可能一段时间会换,自己注意下)。
8080就是端口号了,我们电脑的端口很多,只要用不被占用的就行了。
SmartParking/reg1就是你的SmartParking工程下的某一个servlet,我们通过reg1将真实地址隐藏了(我这里学的不是很明白,懂得应该都能懂,没有学过servlet的建议去B站找找servlet的资源听一下,很简单的,听两节servlet基础就行了)。
反正经过上面的东东,我们就可以访问到我们自己的服务器资源了。
先把代码列出来(需要自己导入JDBK数据库操作的jar包),简单说一下:就是客户端通过OKhttp发送数据给服务器(这一步就是请求request),服务器如果成功接受了数据,就会首先分析该请求是get还是post,然后在根据他的类型执行不同的方法,get请求执行doGet方法,post请求执行doPost方法(我上传的是post请求,所以只对doPost方法进行了编写)。最后执行完相应的方法之后就会返回响应给客户端,响应数据的写入也在doGet和doPost方法中写,核心内容方法是getWriter().write()。
代码中的DBHandle是封装的连接数据库以及curd方法。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.gson.Gson; public class RegisterServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.service(req, resp); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); resp.addIntHeader("ycy", 101); System.out.println(req.getRequestURI()); BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)req.getInputStream(), "utf-8")); StringBuffer sb = new StringBuffer(""); String temp,json; while ((temp = br.readLine()) != null) { sb.append(temp); } br.close(); json = sb.toString(); Gson gson = new Gson(); User user = gson.fromJson(json, User.class); String uname = user.getUname(); String pwd = user.getPwd(); boolean u_exit = false; u_exit = exit(uname,u_exit); if(u_exit) { insert(uname, pwd); resp.getWriter().write("success"); }else { resp.getWriter().write("failure"); } } private boolean exit(String uname,boolean b_exit) { DBHandler db_exit = new DBHandler(); String sql_select = "select *from user where username=?"; String a_exit = db_exit.query(sql_select, new String[] {uname}); /* //判断获得的数据库数据中的username所在的索引区间,username是第一行数据,所有只用判断第一个分节符*所在位置即可 int a = a_exit.indexOf("*"); //如果a是-1,表明数据库中没有该username注册,如果不是-1;返回该索引值前的字符串 if(a != -1) { b_exit = a_exit.substring(0,a); return b_exit; }else { return null; }*/ /* //上面这个方法感觉很不方便,是否可以这样,通过索引值是否为-1就可以判断啊,如果是-1则不存在,不然就是存在的,没必要进行其他操作。 int a = a_exit.indexOf("*"); //如果a是-1,表明数据库中没有该username账号注册,b_exit为真;如果不是-1,则证明数据库中已经注册过该账号 if(a != -1) { b_exit = false; return b_exit; }else { b_exit = true; return b_exit; }*/ //上面这个方法也不行,我们直接判断a_exit是否为空不就好了吗 //如果a是-1,表明数据库中没有该username账号注册,b_exit为真;如果不是-1,则证明数据库中已经注册过该账号 if(a_exit.isEmpty()) { b_exit = true; return b_exit; }else { b_exit = false; return b_exit; } } private void insert(String uname, String pwd) { DBHandler db_insert = new DBHandler(); String sql = "insert into user(username,pwd) values (?,?)"; db_insert.insert(sql, new String[] {uname, pwd}); } }
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import javax.servlet.http.HttpServlet; public class DBHandler { String url = "jdbc:mysql://localhost/parking"; String user="root"; String pwd="Qwert592665"; private Connection conn; private PreparedStatement ps; private ResultSet rs; public Connection getConn(){ try{ Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection(url, user, pwd); }catch(Exception ex){ ex.printStackTrace(); } return conn; } public String query(String sql,String[] args){ String result=""; try{ conn=getConn(); System.out.println(sql); ps=conn.prepareStatement(sql); for(int i=0;i<args.length;i++){ ps.setString(i+1, args[i]); } rs=ps.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); int count=rsmd.getColumnCount(); System.out.println(count); while (rs.next()) { for(int i=1;i<=count;i++){ result+=rs.getString(i)+"*"; } } }catch (Exception ex) { ex.printStackTrace(); } return result; } public boolean insert(String sql,String[] args){ boolean flag=false; try{ conn=getConn(); System.out.println(sql); ps=conn.prepareStatement(sql); for(int i=0;i<args.length;i++){ ps.setString(i+1, args[i]); } int i=ps.executeUpdate(); System.out.println(i); if(i==1){ flag=true; } }catch (Exception ex) { ex.printStackTrace(); } return flag; } public boolean checkUser(String sql,String[] args){ boolean flag=false; try{ conn=getConn(); ps=conn.prepareStatement(sql); for(int i=0;i<args.length;i++){ ps.setString(i+1, args[i]); } rs=ps.executeQuery(); if(rs.next()){ flag=true; } }catch (Exception ex) { ex.printStackTrace(); } return flag; } public static void main(String[] args){ DBHandler dbh=new DBHandler(); String result=dbh.query( "select * from book where book_name like ? or book_author like ?", new String[] { "wandou", "123456" }); System.out.println(result); } }
5、最终调试
调试过程遇到很多问题就要自己解决了,但是首先应该明白一点就是要用TCP/IP Monitor来看自己的数据对不对。
左下角和右下角分别是你的request和response,里面有你的响应头和数据,首先分析自己发送的东西有没有问题,最后写东西。
6、源码