零基础小白开发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<>();
ListView listView = (ListView)findViewById(R.id.listView);
Map<String, Object> item;
final List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
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")
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
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){
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<>();
ListView listView = (ListView)findViewById(R.id.listView);
Map<String, Object> item;
final List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
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")
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
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){
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 ListView msgListView;
private EditText inputText;
private Button send;
private MsgAdapter adapter;
private List<Msg> msgList = new ArrayList<Msg>();
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);
Title.setText(title);
initMsgs();
adapter = new MsgAdapter(Chatting.this, R.layout.msg_item, msgList);
inputText = (EditText) findViewById(R.id.input_text);
send = (Button) findViewById(R.id.send);
msgListView = (ListView) findViewById(R.id.msg_list_view);
msgListView.setAdapter(adapter);
send.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String content = inputText.getText().toString();
if(!"".equals(content))
{
Msg msg = new Msg(content , Msg.TYPE_SEND);
msgList.add(msg);
adapter.notifyDataSetChanged();
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() {
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.add(msg1);
}
else
{
Msg msg1 = new Msg(temp1.getText(),Msg.TYPE_RECEIVED);
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){
end = System.currentTimeMillis();
}
System.out.println("end = " + end);
System.out.println("end - start = " + (end - start));
}
}
聊天界面显示大概是这样(比较简陋):
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-
|