零基础小白开发app日志–“菜根易嚼”交易平台 第二章 前端功能具体实现以及前后端交互实现

零基础小白开发app日志–“菜根易嚼”交易平台 第二章 前端功能具体实现以及前后端交互实现


前言

整个工作,在五月份就已经完成了,远端服务器也在阿里云上配置了个简易的。这个软件app是已经能够部署到云端,进行使用,功能的话除了支付我们没有权限,也设涉及到法律,其它的相当于一个简单的咸鱼了。但是之后一直有事情耽搁,没有来得及更新,现在来回忆就发现已经忘记了不少了。为了防止以后忘记的更多,还是决定现在来把还能记得住的部分记录下来。


一、云端与app的信息交互实现?

1、网络权限的开通

我们由于没有学过计网,其实在这方面缺少一些关键知识,走了不少弯路,出了不少莫名其妙的bug,后来发现应该一开始就把网络传输的权限配置好。在Android前端的架构中,是需要去添加网络传输的权限的,我们采用的传输协议是okhttp。

在build.gradle文件的dependcies中要加入okhttp3的依赖,如下所示


```javascript
dependencies {
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.viewpager:viewpager:1.0.0'
    implementation 'com.android.support:recyclerview-v7:30.0.3'
    implementation 'com.squareup.okhttp3:okhttp:3.4.1'
    implementation 'com.squareup.okio:okio:3.0.0-alpha.1'
    implementation files('src\\main\\libs\\mysql-connector-java-5.1.30-bin.jar')
    implementation files('src\\main\\libs\\commons-beanutils-1.9.4.jar')
    implementation files('src\\main\\libs\\commons-collections4-4.4.jar')
    implementation files('src\\main\\libs\\commons-lang-2.6.jar')
    implementation files('src\\main\\libs\\commons-logging-1.2.jar')
    implementation files('src\\main\\libs\\ezmorph-1.0.6.jar')
    implementation files('src\\main\\libs\\json-lib-2.1-jdk15.jar')
    implementation files('src\\main\\libs\\fastjson-1.2.76.jar')
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

在AndroidManifest.xml文件里也要加入,准许app连接网络的权限,如下所示:

 <uses-permission android:name="android.permission.INTERNET"/>

接着,在res文件夹中的xml文件夹中,要再创建一个名为network_security_config.xml的文件,内容如下:

 <?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

2、统一前端和后端的数据类型,以及商议统一命名

我们一开始前后端是分开写的,在一些类以及类属性上的命名有很大差异,这给进行前后端交互的时候,带来不少的困难,后期还是要统一命名,或者至少约定统一的规则。下面以商品类的统一建立为例:

 package com.skypan.easytochewroot;

public class Goods {
    private  String goodid;
    private String title;
    private String post_userid;
    private String kind;
    private String time;
    private String price;
    private String contact;
    private String info;
    private String picturechar;


    public String getGoodid() {
        return goodid;
    }

    public void setGoodid(String goodid) {
        this.goodid = goodid;
    }
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getPost_userid() {
        return post_userid;
    }

    public void setPost_userid(String post_userid) {
        this.post_userid = post_userid;
    }

    public String getKind() {
        return kind;
    }

    public void setKind(String kind) {
        this.kind = kind;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time= time;
    }
    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }
    public String getContact() {
        return contact;
    }

    public void setContact(String contact) {
        this.contact = contact;
    }
    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
    public String getPicturechar() {
        return picturechar;
    }

    public void setPicturechar(String picturechar) {
        this.picturechar = picturechar;
    }
}

3、传输信息到远端服务器

下面以点击注册按钮,如果是初学者或者完全没有接触过,这类代码需要好好研究看懂,不然接收和发送一起的进程,或者图片传输会无法运用。下面以发送用户账号密码给云端服务器为例:

 public void onClick(View v) {
                user=User.getText().toString();
                password1=Password1.getText().toString();
                password2=Password2.getText().toString();
                if(user==null||user.equals("")){
                    Toast.makeText(getApplicationContext(), "请输入用户学号!", Toast.LENGTH_SHORT).show();
                }
                else if(password1==null||password1.equals("")){
                    Toast.makeText(getApplicationContext(), "请输入密码!", Toast.LENGTH_SHORT).show();
                }
                else if(!password1.equals(password2)){
                    Toast.makeText(getApplicationContext(), "两次输入的密码不一致!", Toast.LENGTH_SHORT).show();
                }


                else {
                    new Thread(()->{
                        OkHttpClient okHttpClient = new OkHttpClient();
                        FormBody formBody = new FormBody.Builder().add("id", user).add("password",password1).build();

                        Request request = new Request.Builder()
                                .url("http://121.43.181.253:8080/user/register")
                                .post(formBody)
                                .build();
                        try (Response response = okHttpClient.newCall(request).execute()) {
                            Looper.prepare();
                            if (Boolean.parseBoolean(response.body().string()))
                            {
                                Toast.makeText(getApplicationContext(), "注册成功", Toast.LENGTH_SHORT).show();
                                Intent intent = new Intent(Register.this,login.class);

                                startActivity(intent);
                            }
                            else
                            {
                                Toast.makeText(getApplicationContext(), "注册失败", Toast.LENGTH_SHORT).show();
                            }
                            Looper.loop();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }).start();};
            }

4、接收云端服务器数据并展示

下面是一段,在主页接收并显示已经发布的商品的信息(此中包含图片传输,后文细说):

private void init(){
        mListView = findViewById(R.id.listView);
        mListItems = new ArrayList<>();
        //DatabaseHelper database = new DatabaseHelper(this);
        //SQLiteDatabase db = database.getWritableDatabase();
        ListView listView = (ListView)findViewById(R.id.listView);
        Map<String, Object> item;  // 列表项内容用Map存储
        final List<Map<String, Object>> data = new ArrayList<Map<String, Object>>(); // 列表
       // Cursor cursor = db.query("iteminfo",null,null,null,null,null,null,null); // 数据库查询
       /* if (cursor.moveToFirst()){
            while (!cursor.isAfterLast()){
                mMap = new HashMap<>();
                mMap.put("id",cursor.getInt(0));
                mMap.put("userid",cursor.getString(1));
                mMap.put("title",cursor.getString(2));
                mMap.put("kind",cursor.getString(3));
                mMap.put("info",cursor.getString(4));
                mMap.put("price",cursor.getString(5));
                mMap.put("image", mImageId[1]);
                cursor.moveToNext();
                data.add(mMap); // 加入到列表中
            }
        }
        cursor.close();*/


       Thread t= new Thread(()->{
            OkHttpClient okHttpClient = new OkHttpClient();
            FormBody formBody = new FormBody.Builder().build();
            Request request = new Request.Builder()
                    .url("http://121.43.181.253:8080/merch/each")
                   // .post(formBody)
                    .build();

            try (Response response = okHttpClient.newCall(request).execute()) {

               // String mmp="[{\"title\":\"1\",\"post_userid\":\"22\",\"kind\":\"33\",\"time\":\"44\",\"price\":\"55\",\"contact\":\"66\",\"info\":\"77\",\"picturechar\":\"88\"}]";
               // String test =response.body().string();
                //List<Goods> data1 = JSONArray.parseArray(mmp,Goods.class);
               // List<Goods> data1 = new ArrayList<Goods>();
              List<Goods> data1 = JSONArray.parseArray(response.body().string(),Goods.class);
                data2=data1;

                for (int i = 0; i < data1.size(); ++ i){
                    mMap = new HashMap<>();
                    Goods temp= data1.get(i);
                    mMap.put("id",temp.getGoodid());
                    mMap.put("userid",temp.getPost_userid());
                    mMap.put("title",temp.getTitle());
                    mMap.put("kind",temp.getKind());
                    mMap.put("info",temp.getInfo());
                    mMap.put("price",temp.getPrice());
                    String picturechar1=temp.getPicturechar();
                    byte[] bitmapArray =Base64.decode(picturechar1, Base64.DEFAULT);
                    Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length);
                    mMap.put("image", bitmap);
                    data.add(mMap); // 加入到列表中
                }



               String pause="pause";
            } catch (IOException e) {
                e.printStackTrace();
            }

        });
        long start = System.currentTimeMillis();
        System.out.println("start = " + start);
        t.start();
        long end = 0;
        while(t.isAlive() == true){//t.getState() != State.TERMINATED这两种判断方式都可以
            end = System.currentTimeMillis();
        }
        System.out.println("end = " + end);
        System.out.println("end - start = " + (end - start));


        aAdapter = new SimpleAdapter(this, data, R.layout.listview_item_my, new String[]{"title", "image","kind","info","price"}, new int[]{R.id.title, R.id.item_image,R.id.kind,R.id.item_info,R.id.price});
                aAdapter.setViewBinder(new SimpleAdapter.ViewBinder() {
                    public boolean setViewValue(View view, Object data,
                                                String textRepresentation) {
                        if (view instanceof ImageView && data instanceof Bitmap) {
                            ImageView image = (ImageView) view;
                            image.setImageBitmap((Bitmap) data);
                            return true;
                        }
                        return false;
                    }
                });

        mListView.setAdapter(aAdapter);


        String pause="pause";

    }

5、图片传输与转换

因为我们的云服务器很简易,算力和空间不够,所以我们图片用的是很笨拙很废时间的传输方式, 如果有更好的方式,请忽略。下面是发布商品的代码,其中逻辑是把图片先转成string类,再string根据base64规则转成bitmap串,发送给远端,而接收的时候将这个过程反过来就可以了。

private void init(){
        mListView = findViewById(R.id.listView);
        mListItems = new ArrayList<>();
        //DatabaseHelper database = new DatabaseHelper(this);
        //SQLiteDatabase db = database.getWritableDatabase();
        ListView listView = (ListView)findViewById(R.id.listView);
        Map<String, Object> item;  // 列表项内容用Map存储
        final List<Map<String, Object>> data = new ArrayList<Map<String, Object>>(); // 列表
       // Cursor cursor = db.query("iteminfo",null,null,null,null,null,null,null); // 数据库查询
       /* if (cursor.moveToFirst()){
            while (!cursor.isAfterLast()){
                mMap = new HashMap<>();
                mMap.put("id",cursor.getInt(0));
                mMap.put("userid",cursor.getString(1));
                mMap.put("title",cursor.getString(2));
                mMap.put("kind",cursor.getString(3));
                mMap.put("info",cursor.getString(4));
                mMap.put("price",cursor.getString(5));
                mMap.put("image", mImageId[1]);
                cursor.moveToNext();
                data.add(mMap); // 加入到列表中
            }
        }
        cursor.close();*/


       Thread t= new Thread(()->{
            OkHttpClient okHttpClient = new OkHttpClient();
            FormBody formBody = new FormBody.Builder().build();
            Request request = new Request.Builder()
                    .url("http://121.43.181.253:8080/merch/each")
                   // .post(formBody)
                    .build();

            try (Response response = okHttpClient.newCall(request).execute()) {

               // String mmp="[{\"title\":\"1\",\"post_userid\":\"22\",\"kind\":\"33\",\"time\":\"44\",\"price\":\"55\",\"contact\":\"66\",\"info\":\"77\",\"picturechar\":\"88\"}]";
               // String test =response.body().string();
                //List<Goods> data1 = JSONArray.parseArray(mmp,Goods.class);
               // List<Goods> data1 = new ArrayList<Goods>();
              List<Goods> data1 = JSONArray.parseArray(response.body().string(),Goods.class);
                data2=data1;

                for (int i = 0; i < data1.size(); ++ i){
                    mMap = new HashMap<>();
                    Goods temp= data1.get(i);
                    mMap.put("id",temp.getGoodid());
                    mMap.put("userid",temp.getPost_userid());
                    mMap.put("title",temp.getTitle());
                    mMap.put("kind",temp.getKind());
                    mMap.put("info",temp.getInfo());
                    mMap.put("price",temp.getPrice());
                    String picturechar1=temp.getPicturechar();
                    byte[] bitmapArray =Base64.decode(picturechar1, Base64.DEFAULT);
                    Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length);
                    mMap.put("image", bitmap);
                    data.add(mMap); // 加入到列表中
                }



               String pause="pause";
            } catch (IOException e) {
                e.printStackTrace();
            }

        });
        long start = System.currentTimeMillis();
        System.out.println("start = " + start);
        t.start();
        long end = 0;
        while(t.isAlive() == true){//t.getState() != State.TERMINATED这两种判断方式都可以
            end = System.currentTimeMillis();
        }
        System.out.println("end = " + end);
        System.out.println("end - start = " + (end - start));


        aAdapter = new SimpleAdapter(this, data, R.layout.listview_item_my, new String[]{"title", "image","kind","info","price"}, new int[]{R.id.title, R.id.item_image,R.id.kind,R.id.item_info,R.id.price});
                aAdapter.setViewBinder(new SimpleAdapter.ViewBinder() {
                    public boolean setViewValue(View view, Object data,
                                                String textRepresentation) {
                        if (view instanceof ImageView && data instanceof Bitmap) {
                            ImageView image = (ImageView) view;
                            image.setImageBitmap((Bitmap) data);
                            return true;
                        }
                        return false;
                    }
                });

        mListView.setAdapter(aAdapter);


        String pause="pause";

    }

二、其他功能具体实现

写不动了,功能还挺多的,就列举聊天和评论两个吧。

1.聊天

我们的聊天功能其实很简易,是把发送的消息在云端增加主键时间,然后显示的话其实就是用时间排序,当然要分清谁是发送者。不想赘述了,直接上代码吧。

信息类的建立代码如下(示例):

package com.skypan.easytochewroot;

public class WXMessage {
    private int icon_id;
    private String title;
    private String msg;
    private String time;

    public WXMessage(){

    }
    public WXMessage(String title, String msg, String time) {
        this.title = title;
        this.msg = msg;
        this.time = time;
    }

    public int getIcon_id() {
        return icon_id;
    }
    public void setIcon_id(int icon_id) {
        this.icon_id = icon_id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getTime() {
        return time;
    }
    public void setTime(String time) {
        this.time = time;
    }

}

信息显示和发送的代码(示例):

package com.skypan.easytochewroot;

import android.app.Activity;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.alibaba.fastjson.JSONArray;
import com.skypan.easytochewroot.Msg;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class Chatting extends Activity {
    private String loginid = login.post_userid;
    private String chatuserid = Item.item_userid;
    private String title = Message_list.message_title;
   // private String title = "myc";
    private ListView msgListView;//定义ListView
    private EditText inputText;//定义EditText
    private Button send;//定义Button
    private MsgAdapter adapter;//定义MsgAdapter
    private List<Msg> msgList = new ArrayList<Msg>();//实例化一个泛型为Msg的List
    private Button but1_m1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chat);
        DatabaseHelper dbhelper1 = new DatabaseHelper(this);
        SQLiteDatabase db=dbhelper1.getReadableDatabase();
        but1_m1=(Button)findViewById(R.id.but1_m1);
        but1_m1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(Chatting.this,Message_list.class));
            }
        });
        TextView Title = (TextView)findViewById(R.id.tt);
        //if(chatuserid==null&&title!=null)
        Title.setText(title);
        //else
        //Title.setText(chatuserid);
        //初始化数据
        initMsgs();

        //调用MsgAdapter的构造方法实例化adapter,
        adapter = new MsgAdapter(Chatting.this, R.layout.msg_item, msgList);
        //分别实例化EditText、Button、ListView
        inputText = (EditText) findViewById(R.id.input_text);
        send = (Button) findViewById(R.id.send);
        msgListView = (ListView) findViewById(R.id.msg_list_view);
        //为ListView加适配器;
        msgListView.setAdapter(adapter);
        //设置send的点击事件,响应用户操作
        send.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                //定义内容获取用户在EditText中输入的字符串
                String content = inputText.getText().toString();

                //如果字符串不为空,把数据添加到 msgList中
                if(!"".equals(content))
                {
                    Msg msg = new Msg(content , Msg.TYPE_SEND);
                    msgList.add(msg);

                    //动态更新ListView
                    adapter.notifyDataSetChanged();

                    //将列表移动到刚发的消息处,即msgList的最大位置
                    msgListView.setSelection(msgList.size());

                    //把输入框置空
                    inputText.setText("");
                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss ");
                    Date curDate = new Date(System.currentTimeMillis());
                    String time = formatter.format(curDate);
                    //存到数据库里
                    new Thread(()->{
                        OkHttpClient okHttpClient = new OkHttpClient();
                        FormBody formBody = new FormBody.Builder()

                                .add("send_id",loginid)
                                .add("receive_id",title)
                                .add("text",content)
                                .build();

                        Request request = new Request.Builder()
                                .url("http://121.43.181.253:8080/message/new")
                                .post(formBody)
                                .build();
                        try (Response response = okHttpClient.newCall(request).execute()) {
                            Looper.prepare();
                            if (Boolean.parseBoolean(response.body().string()))
                            {

                                Toast.makeText(getApplicationContext(), "发布成功", Toast.LENGTH_SHORT).show();
                                Intent intent_=new Intent(Chatting.this,Chatting.class);
                                startActivity(intent_);
                            }
                            else
                            {
                                Toast.makeText(getApplicationContext(), "发布失败", Toast.LENGTH_SHORT).show();
                            }
                            Looper.loop();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }).start();
                }
            }
        });
    }

    private void initMsgs() {
        // TODO Auto-generated method stub
        //从远程数据库中读取数据
        //比如说读出来的还是一个list
        //那么要做到的是遍历这个list,根据login——id 处于的位置,判断是发送的还是接受的
        String userid = login.post_userid;

        //遍历
        //如果是作为发送人


        Thread t= new Thread(()->{
            OkHttpClient okHttpClient = new OkHttpClient();
            FormBody formBody = new FormBody.Builder()
                    .add("id1",loginid)
                    .add("id2",title)
                    .build();
            Request request = new Request.Builder()
                    .url("http://121.43.181.253:8080/message/chat")
                    .post(formBody)
                    .build();

            try (Response response = okHttpClient.newCall(request).execute()) {

                List<Message> data1 = JSONArray.parseArray(response.body().string(),Message.class);


                for (int i = 0; i < data1.size(); ++ i)
                {
                    Message temp1=data1.get(i);
                    if(temp1.getSend_id().equals(loginid))
                    {   // 为列表项赋值
                        Msg msg1 = new Msg(temp1.getText(),Msg.TYPE_SEND);//往msgList中添加发送数据

                        msgList.add(msg1);
                    }
                    else
                    {
                        Msg msg1 = new Msg(temp1.getText(),Msg.TYPE_RECEIVED);//往msgList中添加发送数据

                        msgList.add(msg1);
                    }
                }
                String pause="pause";
            } catch (IOException e) {
                e.printStackTrace();
            }

        });
        long start = System.currentTimeMillis();
        System.out.println("start = " + start);
        t.start();
        long end = 0;
        while(t.isAlive() == true){//t.getState() != State.TERMINATED这两种判断方式都可以
            end = System.currentTimeMillis();
        }
        System.out.println("end = " + end);
        System.out.println("end - start = " + (end - start));

      // Msg msg2 = new Msg("Hello,Who is that?",Msg.TYPE_SEND);//往msgList中添加发送数据

     //   msgList.add(msg2);
        //反之
      //  Msg msg1 = new Msg("Hello guy!",Msg.TYPE_RECEIVED);//往msgList中添加接收数据
      //  msgList.add(msg1);
                 /*Msg msg1 = new Msg("Hello guy!",Msg.TYPE_RECEIVED);//往msgList中添加接收数据
                 msgList.add(msg1);
                 msgList.add(new Msg("Hello!",Msg.TYPE_RECEIVED));
                 Msg msg2 = new Msg("Hello,Who is that?",Msg.TYPE_SEND);//往msgList中添加发送数据
                 msgList.add(msg2);
                Msg msg3 = new Msg("This is Tom,Nice talking to you.",Msg.TYPE_RECEIVED);//往msgList中添加接收数据
                 msgList.add(msg3);*/
    }


}

聊天界面显示大概是这样(比较简陋):
在这里插入图片描述

2.商品评论

添加评论的代码如下(示例):

  new Thread(()->{
                    OkHttpClient okHttpClient = new OkHttpClient();
                    FormBody formBody = new FormBody.Builder()
                            .add("userId",post_userid)
                            .add("itemId",itemid)
                            .add("comment",submit_comment)
                            .add("time",time)
                            .build();

                    Request request = new Request.Builder()
                            .url("http://121.43.181.253:8080/comment/add")
                            .post(formBody)
                            .build();
                    try (Response response = okHttpClient.newCall(request).execute()) {
                        Looper.prepare();
                        if (Boolean.parseBoolean(response.body().string()))
                        {
                            Log.i("1","评论成功");
                            Toast.makeText(getApplicationContext(), "评论成功", Toast.LENGTH_SHORT).show();
                            Intent intent_=new Intent(Item.this,Item.class);
                            intent_.putExtra("id",intent.getStringExtra("id"));
                            startActivity(intent_);
                        }
                        else
                        {
                            Toast.makeText(getApplicationContext(), "添加失败", Toast.LENGTH_SHORT).show();
                        }
                        Looper.loop();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).start();

独立商品页大概这样:
在这里插入图片描述


总结

提示:这里对文章进行总结:
这个软件工程也是告一段落了,3个小白从0开始学,一个月写出这个也是废了不少心思。后端配置我是没有去参与的,所以后端的springboot以及云服务器部署我就不介绍了。

最后附上github的网址(涵盖前后端,前端还包含一个本地版本,即数据库只在本地的):https://github.com/Budian-mao/-app-

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值