让你的APP和你的服务器畅快通讯
做安卓开发有很多时候都是要和web交互的,我们很难制作本地应用,这次把小弟整出来的安卓和服务器通讯贡献出来,希望能帮到需要的朋友,同时也是加深印象。
我们先来搭建安卓客户端,首先写好布局文件:
1.布局文件Register.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/fuction_fond_bg"
- android:orientation="vertical" >
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:src="@drawable/setting_btn" >
- </ImageView>
- <ScrollView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:orientation="vertical" >
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="请输入您的注册信息:"
- android:textColor="#6495ED"
- android:textSize="20dip" >
- </TextView>
- <View
- android:layout_width="fill_parent"
- android:layout_height="2dip"
- android:background="#FF909090" />
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_margin="20dip"
- android:background="#FFFFFF"
- android:orientation="vertical"
- android:padding="10dp" >
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="帐 号: "
- android:textColor="#6495ED" >
- </TextView>
- <EditText
- android:id="@+id/username"
- android:layout_width="190dip"
- android:layout_height="wrap_content" >
- </EditText>
- </LinearLayout>
- <View
- android:layout_width="fill_parent"
- android:layout_height="2dip"
- android:background="#FF909090" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="密 码: "
- android:textColor="#6495ED" >
- </TextView>
- <EditText
- android:id="@+id/password"
- android:layout_width="190dip"
- android:layout_height="wrap_content"
- android:password="true" >
- </EditText>
- </LinearLayout>
- <View
- android:layout_width="fill_parent"
- android:layout_height="2dip"
- android:background="#FF909090" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="确认密码 : "
- android:textColor="#6495ED" >
- </TextView>
- <EditText
- android:id="@+id/confirmpsw"
- android:layout_width="190dip"
- android:layout_height="wrap_content"
- android:password="true" >
- </EditText>
- </LinearLayout>
- <View
- android:layout_width="fill_parent"
- android:layout_height="2dip"
- android:background="#FF909090" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="昵 称: "
- android:textColor="#6495ED" >
- </TextView>
- <EditText
- android:id="@+id/nikename"
- android:layout_width="190dip"
- android:layout_height="wrap_content" >
- </EditText>
- </LinearLayout>
- <View
- android:layout_width="fill_parent"
- android:layout_height="2dip"
- android:background="#FF909090" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- android:text="性 别: "
- android:textColor="#6495ED" >
- </TextView>
- <RadioGroup
- android:id="@+id/gender_group_rb"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <RadioButton
- android:id="@+id/male_rb"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="男 "
- android:textColor="#6495ED" >
- </RadioButton>
- <RadioButton
- android:id="@+id/female_rb"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="女"
- android:textColor="#6495ED" >
- </RadioButton>
- </RadioGroup>
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" >
- </ImageView>
- </LinearLayout>
- <View
- android:layout_width="fill_parent"
- android:layout_height="2dip"
- android:background="#FF909090" />
- <Button
- android:id="@+id/register_btn"
- android:layout_width="fill_parent"
- android:layout_height="40dp"
- android:layout_margin="10dp"
- android:background="@drawable/new_button_bg"
- android:gravity="center"
- android:text="注 册" />
- </LinearLayout>
- </LinearLayout>
- </ScrollView>
- </LinearLayout>
2.Activity文件:RegisterActivity.java
为了让大家看得方便,我逐个为大家讲解:
1.初始化视图控件:
- /**
- * 初始化视图控件
- */
- private void initView() {
- username_et = (EditText) findViewById(R.id.username);
- password_et = (EditText) findViewById(R.id.password);
- confirmpsw_et = (EditText) findViewById(R.id.confirmpsw);
- nikename_et = (EditText) findViewById(R.id.nikename);
- register_btn = (Button) findViewById(R.id.register_btn);
- register_btn.setOnClickListener(listener);
- gender_group_rb = (RadioGroup) findViewById(R.id.gender_group_rb);
- gender_group_rb.setOnCheckedChangeListener(checkListener);
- }
2.当我们填写好数据后,点击注册按钮,调用注册这个方法:
- /**
- * 注册按钮的点击
- */
- private OnClickListener listener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- doRegister();
- }
- };
- /**
- * 开始注册
- */
- private void doRegister() {
- pd = ProgressDialog.show(RegisterActivity.this, "正在注册..",
- "正在注册中..请稍后....", true, true);
- // 1.获取数据
- username = username_et.getText().toString();
- password = password_et.getText().toString();
- confirmpsw = confirmpsw_et.getText().toString();
- nickname = nikename_et.getText().toString();
- // 2.进行校验,不对返回,否则继续
- if (checkNull(username) || checkNull(password) || checkNull(confirmpsw)
- || checkNull(gender) || checkNull(nickname)) {
- Toast.makeText(this, "请填写完整数据", Toast.LENGTH_SHORT).show();
- // TODO 这里本应该完整校验的,暂时偷懒
- return;
- }
- // 3.开始向服务器注册
- Thread thread = new Thread(registerRunnable);
- thread.start();
- }
因为做的比较简陋,详细的表单校验没有写,点击注册开启一个子线程来处理和服务器打交道的耗时操作。在注册的过程中用的httpUrlConnection连接服务器,向服务器提交注册信息。
- /**
- * 开始注册的线程
- */
- Runnable registerRunnable = new Runnable() {
- @Override
- public void run() {
- // 1.拼装数据
- StringBuilder sb = new StringBuilder();
- sb.append("<users>");
- sb.append("<user>");
- sb.append("<username>");
- sb.append(username);
- sb.append("</username>");
- sb.append("<password>");
- sb.append(password);
- sb.append("</password>");
- sb.append("<nickname>");
- sb.append(nickname);
- sb.append("</nickname>");
- sb.append("<gender>");
- sb.append(gender);
- sb.append("</gender>");
- sb.append("</user>");
- sb.append("</users>");
- // 2.开始写数据
- byte content[] = sb.toString().getBytes();
- try {
- URL url = new URL(Constant.REGISTER_SERVLET);
- HttpURLConnection conn = (HttpURLConnection) url
- .openConnection();
- conn.setDoInput(true);
- conn.setDoOutput(true);
- conn.setRequestMethod("POST");
- conn.setRequestProperty("Content-Type", "mutipart/form-data");
- conn.setRequestProperty("Content-Length", content.length + "");
- conn.getOutputStream().write(content);
- // 3.获取服务器返回的数据
- if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
- InputStream in = conn.getInputStream();
- RegisterResultTool resultTool = new RegisterResultTool();
- String result = resultTool.getResultFromInputStream(in);
- // 4.提交结果
- Message msg = new Message();
- msg.obj = result;
- msg.what = 200;
- registerResultHandler.sendMessage(msg);
- }
- } catch (IOException e) {
- Message msg = new Message();
- msg.what = 400;
- registerResultHandler.sendMessage(msg);
- e.printStackTrace();
- }
- pd.cancel();
- }
- };
向服务器提交数据后,服务器会返回一些结果数据,我们就需要处理这些结果数据:
- /**
- * 处理服务器返回结果的类
- *
- * @author Larson
- *
- */
- private class RegisterResultTool {
- /**
- * 从服务器返回的数据中读取返回结果
- *
- * @param in
- * @return
- */
- public String getResultFromInputStream(InputStream in) {
- String result = "";
- SAXParserFactory sf = SAXParserFactory.newInstance();
- try {
- XMLReader xr = sf.newSAXParser().getXMLReader();
- RegisterResultHandler rrh = new RegisterResultHandler();
- xr.setContentHandler(rrh);
- xr.parse(new InputSource(in));
- result = rrh.getResult();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
- }
- /**
- * 因为服务器返回的是xml形式,所以需要解析
- *
- * @author Larson
- *
- */
- private class RegisterResultHandler extends DefaultHandler {
- /**
- * 获得的服务器返回结果
- */
- private String result;
- /**
- * 临时存取数据的变量
- */
- private String var="";
- /**
- * 获取返回值
- *
- * @return
- */
- public String getResult() {
- return result;
- }
- @Override
- public void startElement(String uri, String localName, String qName,
- Attributes attributes) throws SAXException {
- super.startElement(uri, localName, qName, attributes);
- }
- @Override
- public void characters(char[] ch, int start, int length)
- throws SAXException {
- var += new String(ch, start, length);
- super.characters(ch, start, length);
- }
- @Override
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- /**
- * 取出info标签的数据(服务器返回的注册结果)
- */
- if (qName.equals("info")) {
- result = var.trim();
- }
- super.endElement(uri, localName, qName);
- }
- }
获取结果后,在handler中刷新ui通知用户:
- /**
- * 处理返回结果的handler
- * 如果返回的数据是服务器给的成功数据,注册成功,否则就是服务器有问题
- */
- private Handler registerResultHandler = new Handler() {
- public void handleMessage(Message msg) {
- System.out.println(msg.obj+"-------------"+msg.what);
- switch (msg.what) {
- case 400:
- Toast.makeText(RegisterActivity.this, "注册失败.", Toast.LENGTH_SHORT).show();
- break;
- case 200:
- String str = (String) msg.obj;
- if(str.contains("regist_ok"))
- Toast.makeText(RegisterActivity.this, "注册成功.", Toast.LENGTH_SHORT).show();
- else
- Toast.makeText(RegisterActivity.this, "服务器未开放.", Toast.LENGTH_SHORT).show();
- break;
- default:
- break;
- }
- };
- };
接下来我们来写服务器端:
服务器段用registerServlet处理客户端请求:registerServlet.java:
- package com.larson.pm;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.PrintWriter;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.larson.tools.RegisterResultTool;
- public class RegisterServlet extends HttpServlet {
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- }
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //1.获取输入输出流
- response.setContentType("text/html;charset=UTF-8");
- PrintWriter out = response.getWriter();
- InputStream in = request.getInputStream();
- //2.处理客户端发送的数据
- RegisterResultTool tool = new RegisterResultTool();
- String result = tool.register(in);
- //3.向客户端写相应数据
- out.write(result);
- out.flush();
- out.close();
- in.close();
- }
- }
servlet拿到客户端的数据inputStream,用一个工具类RegisterResultTool.java处理这些数据:
- package com.larson.tools;
- import java.io.InputStream;
- import javax.xml.parsers.SAXParserFactory;
- import org.xml.sax.InputSource;
- import org.xml.sax.XMLReader;
- import com.larson.bean.UserInfo;
- import com.larson.daoimpl.UserDao;
- import com.larson.handler.RegisterHandler;
- /**
- * 处理客户端发送过来数据的类
- *
- * @author Larson
- *
- */
- public class RegisterResultTool {
- /**
- * 处理客户端发送过来数据的类
- * @param in
- * 客户端的流
- * @return 处理结果
- */
- public String register(InputStream in) {
- String result = null;
- StringBuilder sb = new StringBuilder();
- //1.获取解析工厂
- SAXParserFactory factory = SAXParserFactory.newInstance();
- XMLReader reader= null;
- try {
- //2.自定义解析过程
- reader = factory.newSAXParser().getXMLReader();
- RegisterHandler handler = new RegisterHandler();
- reader.setContentHandler(handler);
- //3.开始解析客户端过来的输入流,并把数据封装到userInfo的bean中
- reader.parse(new InputSource(in));
- UserInfo user = handler.getUser();
- //4.往服务器的数据库添加一条用户信息
- UserDao dao = new UserDao();
- dao.add(user);
- //5.完成后给客户端反馈消息
- sb.append("<info>");
- sb.append("regist_ok");
- sb.append("</info>");
- } catch (Exception e) {
- //TODO 解析失败
- sb.append("<info>");
- sb.append("regist_fail");
- sb.append("</info>");
- e.printStackTrace();
- }
- result = sb.toString();
- return result;
- }
- }
再次过程中,我们需要自定义一个sax解析xml的handler对数据进行处理封装到bean文件中:
RegisterHandler.java:
- package com.larson.handler;
- import org.xml.sax.Attributes;
- import org.xml.sax.SAXException;
- import org.xml.sax.helpers.DefaultHandler;
- import com.larson.bean.UserInfo;
- public class RegisterHandler extends DefaultHandler {
- private UserInfo user;
- private String var="";
- @Override
- public void startElement(String uri, String localName, String qName,
- Attributes attributes) throws SAXException {
- //遇到user标签就表示是一个user对象
- if(qName.equals("user"))
- user = new UserInfo();
- super.startElement(uri, localName, qName, attributes);
- }
- @Override
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- if("username".equals(qName))
- user.setUsername(var);
- if("password".equals(qName))
- user.setPassword(var);
- if("nickname".equals(qName))
- user.setNickname(var);
- if("gender".equals(qName))
- user.setGender(var);
- //设置完临时属性置空
- var="";
- super.endElement(uri, localName, qName);
- }
- @Override
- public void characters(char[] ch, int start, int length)
- throws SAXException {
- var+=new String(ch, start, length);
- super.characters(ch, start, length);
- }
- /**
- * 获取填充完属性的user对象
- * @return
- */
- public UserInfo getUser() {
- return user;
- }
- }
,处理完毕以后,需要把这些数据写入到数据库,生成一条新的用户信息记录,因此需要些一个UserDao。,而我们习惯性用jdbcutils管理连接,这里为了代码可重用更好,我把所有修改的方法集合到一个update方法里面:JdbcUtils.java:
- package com.larson.tools;
- import java.io.InputStream;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- import java.util.Properties;
- import com.larson.handler.ResultSetHandler;
- /**
- * 数据库相关
- * @author Larson
- *
- */
- public class JdbcUtils {
- // private static ComboPooledDataSource ds = null;
- private static Connection conn;
- static{
- try{
- InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
- Properties properties = new Properties();
- properties.load(in);
- String url = properties.getProperty("url");
- String user = properties.getProperty("user");
- String passwd = properties.getProperty("password");
- String driver = properties.getProperty("driver");
- Class.forName(driver);
- conn = DriverManager.getConnection(url, user, passwd);
- // ds = new ComboPooledDataSource();
- // ds.setDriverClass(driver);
- // ds.setJdbcUrl(url);
- // ds.setUser(user);
- // ds.setPassword(passwd);
- //
- // ds.setInitialPoolSize(10);
- // ds.setMinPoolSize(5);
- // ds.setMaxPoolSize(20);
- //
- // ds = new ComboPooledDataSource();
- }catch (Exception e) {
- throw new ExceptionInInitializerError(e);
- }
- }
- /**
- * 获取连接
- * @return
- * @throws SQLException
- */
- public static Connection getConnection() throws SQLException{
- // return ds.getConnection();
- return conn;
- }
- /**
- * 释放连接
- * @param conn
- * @param st
- * @param rs
- */
- public static void release(Connection conn,Statement st,ResultSet rs){
- if(rs!=null){
- try{
- rs.close();
- }catch (Exception e) {
- e.printStackTrace();
- }
- rs = null;
- }
- if(st!=null){
- try{
- st.close();
- }catch (Exception e) {
- e.printStackTrace();
- }
- }
- if(conn!=null){
- try{
- conn.close();
- }catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 替换dao中的增删改方法
- * @param sql
- * @param params
- * @throws SQLException
- */
- public static void update(String sql,Object params[]) throws SQLException{
- Connection conn = null;
- PreparedStatement st = null;
- ResultSet rs = null;
- try{
- conn = getConnection();
- st = conn.prepareStatement(sql);
- for(int i=0;i<params.length;i++){
- st.setObject(i+1, params[i]);
- }
- st.executeUpdate();
- }finally{
- release(conn, st, rs);
- }
- }
- /**
- * 替换所有dao中的查询 策略模式
- * @param sql
- * @param params
- * @param rsh
- * @return
- * @throws SQLException
- */
- public static Object query(String sql,Object params[],ResultSetHandler rsh) throws SQLException{
- Connection conn = null;
- PreparedStatement st = null;
- ResultSet rs = null;
- try{
- conn = getConnection();
- st = conn.prepareStatement(sql);
- for(int i=0;i<params.length;i++){
- st.setObject(i+1, params[i]);
- }
- rs = st.executeQuery();
- return rsh.handler(rs);
- }finally{
- release(conn, st, rs);
- }
- }
- }
然后便是UserDao.java:
- package com.larson.daoimpl;
- import com.larson.bean.UserInfo;
- import com.larson.exception.DaoException;
- import com.larson.handler.BeanHandler;
- import com.larson.tools.JdbcUtils;
- public class UserDao {
- public void add(UserInfo user) {
- try {
- String sql = "insert into user(username,password,gender,nickname) values(?,?,?,?)";
- Object params[] = { user.getUsername(),
- user.getPassword(), user.getGender(),user.getNickname() };
- for(Object obj:params)
- System.out.println("userdao add---"+obj);
- JdbcUtils.update(sql, params);
- } catch (Exception e) {
- throw new DaoException(e);
- }
- }
- public void update(UserInfo user) {
- try {
- String sql = "update user set user=?,password=?,gender=?,nickname=? where id=?";
- Object params[] = { user.getId(), user.getUsername(),
- user.getPassword(), user.getNickname(), user.getId() };
- JdbcUtils.update(sql, params);
- } catch (Exception e) {
- throw new DaoException(e);
- }
- }
- public void delete(String id) {
- try {
- String sql = "delete from user where id=?";
- Object params[] = { id };
- JdbcUtils.update(sql, params);
- } catch (Exception e) {
- throw new DaoException(e);
- }
- }
- public UserInfo find(String id) {
- try {
- String sql = "select * from user where id=?";
- Object params[] = { id };
- return (UserInfo) JdbcUtils.query(sql, params, new BeanHandler(
- UserInfo.class));
- } catch (Exception e) {
- throw new DaoException(e);
- }
- }
- }
为了方便,我把bean文件也贴出来:
userInfo.java:
- package com.larson.bean;
- public class UserInfo {
- private int id;
- private String username;
- private String password;
- private String gender;
- private String nickname;
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public String getGender() {
- return gender;
- }
- public void setGender(String gender) {
- this.gender = gender;
- }
- public String getNickname() {
- return nickname;
- }
- public void setNickname(String nickname) {
- this.nickname = nickname;
- }
- }
本来准备用数据库连接池的,可是老是报错,就是上面注释的那几行,有懂的人麻烦告诉我,感激不尽。