源码地址:https://download.csdn.net/download/m0_51152186/85687858
1.项目的需求(前后台功能需求,数据库的需求)
1.1 前后台功能
1.1.1 注册
用户通过安卓前端输入框输入注册账号信息(姓名、电话和密码),之后将用户信息存储到后台服务器中完成注册
1.1.2 登录
用户在安卓前端输入框输入电话号和密码,当与后台服务器中数据匹配时,提示登录成功,本地登录后,本地保存用户的登录信息。
1.1.3 同步数据
用户可以将后台服务器的数据下载到本地数据库,也可以将本地数据库上传后台服务器的数据库中,上传和下载有进度条显示
1.1.4 记账
用户可以及记录收入和支出两类数据,每一类都要记录:日期,主题,金额,时间及备注。用户可增删改查自己的记账信息。
1.1.5 统计
系统可以分类统计显示每月/每年/总计的收入和支出信息。
1.2 数据库的需求
本项目中一共建了两个数据库表分别为user表和record表
1.2.1 user表结构如图1.2.1
图1.2.1 user表结构图
1.2.2 record表结构如图1.2.2
图1.2.2 record表结构图
2.项目的设计
2.1项目流程图
图2.1 项目流程图
2.2服务端结构
服务端主要运用了Spring、SpringBoot和Mybatis框架进行搭建,具体包如图2.2
图2.2 服务端包结构图
2.3 Android端结构
Android端运用okhttp框架和LitePal框架进行搭建,具体包结构如图2.3
3.关键的代码
3.1服务端主要代码
3.1.1 数据库连接代码
#DB Configuration:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/accountbook?serverTimezone=CTT&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=123456
server.port=8080
server.servlet.context-path=/accountbook
3.1.2 Dao层主要代码
//添加一条记录
@Insert("insert into record(id,phoneNumber,category,content,money,status,date) " +
"values (#{record.uuid},#{phoneNumber},#{record.category},#{record.content},#{record.money},0,#{record.date})")
void addRecord(@Param("phoneNumber") String phoneNumber,@Param("record") Record record) throws Exception;
//根据手机号码查询该用户下所有的信息
@Select("SELECT * FROM record WHERE phoneNumber = #{phoneNumber}")
@Results({
@Result(property = "uuid",column = "id",id = true),
@Result(property = "category",column = "category"),
@Result(property = "content",column = "content"),
@Result(property = "money",column = "money"),
@Result(property = "status",column = "status"),
@Result(property = "date",column = "date")
})
List
//删除指定的记录
@Delete("DELETE FROM record WHERE id = #{recordId}")
void deleteRecord(@Param("recordId")String recordId) throws Exception;
//修改服务器中的记录
@Update("UPDATE record SET category=#{category},content=#{content},money=#{money},status=#{status},date=#{dateString} WHERE id = #{uuid}")
void upgradeRecord(Record record) throws Exception;/**
//实现用户注册
@Insert("insert into user(phoneNumber,username,password) values (#{phoneNumber},#{username},#{password})")
public void register(User user) throws Exception;
//用户登录
@Select("SELECT * FROM user WHERE phoneNumber = #{phoneNumber} ")
public User login(User user) throws Exception;
3.1.3service层主要代码
@Override
public ResultInfo
for (Record record : records) {
int status = record.getStatus();
if (status == 1) { //添加数据
System.out.println(record.toString());
recordMapper.addRecord(phoneNumber, record);
} else if (status == 2) { //删除数据
recordMapper.deleteRecord(record.getUuid());
} else if (status == 3) { //修改数据
recordMapper.upgradeRecord(record);
}
}
ResultInfo
resultInfo.setFlag(true);
resultInfo.setData("同步成功");
return resultInfo;
}
@Override
public ResultInfo> downloadRecords(String
phoneNumber) throws Exception {
List
ResultInfo>
resultInfo = new ResultInfo<>();
resultInfo.setFlag(true);
resultInfo.setData(records);
return resultInfo;
}
}
@Override
public ResultInfo
userMapper.register(user);
ResultInfo
resultInfo.setFlag(true);
resultInfo.setData("注册成功");
return resultInfo;
}
@Override
public ResultInfo
User loginUser = userMapper.login(user);
ResultInfo
resultInfo.setFlag(true);
resultInfo.setData(loginUser);
return resultInfo;
3.2Android主要代码
3.2.1布局文件
主界面:activity_main.xml
xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/main_drawer"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="@color/back_gray"
android:orientation="vertical">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="?attr/colorPrimary">
<ImageView
android:id="@+id/start_navigation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:src="@drawable/catalog"/>
<Button
android:id="@+id/currentDate"
android:background="#00ffffff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@color/white"
android:drawableRight="@drawable/arrows"
android:textSize="20sp"
android:text="0000年00月"/>
<ImageView
android:id="@+id/into_overview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="@drawable/overview"
android:layout_marginRight="10dp"/>
RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_record_fab"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/add" />
androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/nav_menu" />
androidx.drawerlayout.widget.DrawerLayout>
添加账单界面:activity_add_modify_record.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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".AddAndModifyRecordActivity"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="?attr/colorPrimary">
<ImageView
android:id="@+id/back_to_main_"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:src="@drawable/ic_back" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginRight="50dp">
<TextView
android:id="@+id/expenditure"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:clickable="true"
android:text="支出"
android:textColor="@color/white"
android:textSize="20dp"
android:textStyle="bold" />
<TextView
android:id="@+id/income"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:clickable="true"
android:text="收入"
android:textColor="@color/white"
android:textSize="20dp"
android:textStyle="bold" />
LinearLayout>
<ImageView
android:id="@+id/save_record"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:clickable="true"
android:src="@drawable/save_yes" />
RelativeLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/add_record_viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:id="@+id/add_record_category_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textSize="20dp"
android:gravity="center"/>
<EditText
android:id="@+id/add_record_content"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="点此输入备注"
android:gravity="center_vertical|right"/>
LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:id="@+id/add_record_date"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textSize="20dp"
android:gravity="center"/>
<EditText
android:id="@+id/add_record_money"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:gravity="center_vertical|right"
android:textColor="@color/red"
android:inputType="number|numberDecimal"
android:hint="点此输入金额"/>
LinearLayout>
LinearLayout>
LinearLayout>
登录界面:activity_login.xml
xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="100dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="300dp"
android:layout_height="50dp"
android:layout_gravity="center" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="账号:" />
<EditText
android:id="@+id/phone_number"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
LinearLayout>
<LinearLayout
android:layout_width="300dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密码:" />
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="textPassword"/>
LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<CheckBox
android:id="@+id/remember_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="记住密码"/>
LinearLayout>
<Button
android:id="@+id/login"
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:background="#f81"
android:textSize="20sp"
android:text="登录"/>
LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp">
<TextView
android:id="@+id/register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:text="立即注册"/>
<TextView
android:layout_width="1dp"
android:layout_height="wrap_content"
android:background="#044"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"/>
<TextView
android:id="@+id/find_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="找回密码"/>
LinearLayout>
RelativeLayout>
3.2.2主要代码
//连接服务器
@Event(R.id.save_setting)
private void myClick(View view) {
switch (view.getId()) {
case R.id.save_setting:
ip = serverIPEt.getText().toString();
if (!TextUtils.isEmpty(ip)) {
editor.putString("ip","http://"+ip+":8080/accountbook");
editor.apply();
ToastUtil.Pop("保存成功");
finish();
}
break;
default:
}
}
//注册
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseString = response.body().string();
final ResultInfo resultInfo = JSONObject.parseObject(responseString, ResultInfo.class);
Log.d(TAG, "onResponse: "+resultInfo.toString());
if (resultInfo.isFlag()) {
runOnUiThread(new Runnable() {
@Override
public void run() {
SharedPreferences.Editor editor = getSharedPreferences("login_info", MODE_PRIVATE).edit();
editor.putString("phone_number", phoneNumber);
editor.apply();
ToastUtil.Pop("注册成功");
startActivity(new Intent(RegisterActivity.this, LoginActivity.class));
finish();
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
ToastUtil.Pop(resultInfo.getErrorMsg());
}
});
}
}
});
}
} else {
ToastUtil.Pop("两次密码不一致");
}
}
//登录
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseString = response.body().string();
final ResultInfo resultInfo = JSONObject.parseObject(responseString,ResultInfo.class);
if (resultInfo.isFlag()) {
editor = preferences.edit();
if (rememberPassword.isChecked()) {
editor.putBoolean("remember_password" , true);
}
editor.putBoolean("already_login" , true);
String loginUserStr = JSONArray.toJSONString(resultInfo.getData());
editor.putString("login_user" , loginUserStr);
editor.apply();
runOnUiThread(new Runnable() {
@Override
public void run() {
ToastUtil.Pop("登录成功");
startActivity(new Intent(LoginActivity.this , MainActivity.class));
finish();
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
ToastUtil.Pop(resultInfo.getErrorMsg());
}
});
}
}
});
} else {
ToastUtil.Pop("用户名或密码不能为空");
}
// 添加和修改Record
@ContentView(R.layout.activity_add_modify_record)
public class AddAndModifyRecordActivity extends AppCompatActivity{
@ViewInject(R.id.add_record_viewpager)
private ViewPager viewPager;
@ViewInject(R.id.add_record_category_name)
private TextView categoryName; //显示当前选择的分类的名称
@ViewInject(R.id.add_record_content)
private EditText contentEdit; //备注
@ViewInject(R.id.add_record_date)
private TextView dateText; //日期
@ViewInject(R.id.add_record_money)
private EditText moneyEdit; //金额
private static final String TAG = "Add_ModifyRecordAct";
private boolean isIncome = false; //true是收入,false是支出
private List pagerList; //ViewPager每一页View的集合
private String dateString; //日期的字符串,1999-04-05
private boolean toModify; //判断当前的操作是否去修改Record,true则修改,false则添加
private Record toModifyRecord; //待修改的数据
private int year;
private int month;
private int day;
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);
try {
toModifyRecord = LitePal.where("uuid = ? ",getIntent().getStringExtra("uuid")).find(Record.class).get(0);
} catch (Exception e) {
//e.printStackTrace();
}
toModify = toModifyRecord!=null;
if (toModify) {
isIncome = toModifyRecord.getMoney()>0;
}
initWidget(); //初始化界面上的控件
initData(); //初始化所需数据
}
/**
* 初始化界面上的控件
*/
private void initWidget() {
//ViewPager
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
//当页面的滑动状态改变时该方法会被触发,页面的滑动状态有3个:“0”表示什么都不做,“1”表示开始滑动,“2”表示结束滑动
@Override
public void onPageScrollStateChanged(int state) {
if (state == 2) {
if (viewPager.getCurrentItem()==0) {
isIncome = false;
} else {
isIncome = true;
}
changeMoneyEditColor();
}
}
});
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void initData() {
//初始化收入分类列表
List incomeList; //收入分类列表
incomeList = new ArrayList<>();
for (int i = 0; i< CategoriesUtils.incomeCategoryName.length ; i++) {
Category category = new Category();
category.setImageId(CategoriesUtils.incomeCategoryIcon[i]);
category.setName(CategoriesUtils.incomeCategoryName[i]);
incomeList.add(category);
}
//初始化支出分类列表
List expenditureList; //支出分类列表
expenditureList = new ArrayList<>();
for (int j = 0; j< CategoriesUtils.expenditureCategoryName.length ; j++) {
Category category = new Category();
category.setImageId(CategoriesUtils.expenditureCategoryIcon[j]);
category.setName(CategoriesUtils.expenditureCategoryName[j]);
expenditureList.add(category);
}
//初始化ViewPager每一页的View的集合
//支出页
pagerList = new ArrayList<>();
RecyclerView recyclerView1 = new RecyclerView(AddAndModifyRecordActivity.this);
StaggeredGridLayoutManager layoutManager1 = new
StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL);
recyclerView1.setLayoutManager(layoutManager1);
recyclerView1.setAdapter(new CategoryAdapter(expenditureList));
pagerList.add(recyclerView1);
//收入页
RecyclerView recyclerView2 = new RecyclerView(AddAndModifyRecordActivity.this);
StaggeredGridLayoutManager layoutManager2 = new
StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView2.setLayoutManager(layoutManager2);
recyclerView2.setAdapter(new CategoryAdapter(incomeList));
pagerList.add(recyclerView2);
//设置适配器
viewPager.setAdapter(new ViewPagerAdapter());
//设置当前的日期
LocalDateTime nowDate = LocalDateTime.now();
dateString = nowDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
year = nowDate.getYear();
month = nowDate.getMonthValue();
day = nowDate.getDayOfMonth();
dateText.setText(dateString);
//如果是修改数据,则将数据填充到页面上
if (toModify) {
categoryName.setText(toModifyRecord.getCategory());
contentEdit.setText(toModifyRecord.getContent());
moneyEdit.setText(String.valueOf(Math.abs(toModifyRecord.getMoney())));
dateString = toModifyRecord.getDateString();
dateText.setText(dateString);
}
}
@Event(value = {R.id.expenditure,R.id.income,R.id.add_record_date,R.id.save_record,R.id.back_to_main_})
private void myClick(View v) throws ParseException {
switch (v.getId()) {
case R.id.expenditure:
viewPager.setCurrentItem(0);
isIncome = false;
changeMoneyEditColor();
break;
case R.id.income:
viewPager.setCurrentItem(1);
isIncome = true;
changeMoneyEditColor();
break;
case R.id.add_record_date:
DatePickerDialog datePickerDialog = new DatePickerDialog(AddAndModifyRecordActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int mYear, int mMonth, int dayOfMonth) {
year = mYear;
month = mMonth+1;
day = dayOfMonth;
dateString = year+"-" + (month<10 ? ("0"+month+"-") : (month+"-")) + (day<10 ? ("0"+day) : (day));
dateText.setText(dateString);
}
},
year, month-1, day);
datePickerDialog.show();
break;
case R.id.save_record:
Date date = new Date(year-1900,month-1,day);
boolean saveSuccess;
String categoryNameStr = categoryName.getText().toString();
String contentStr = contentEdit.getText().toString();
if (toModify) {
Log.d(TAG, toModifyRecord.toString());
toModifyRecord.setCategory(categoryName.getText().toString());
toModifyRecord.setContent(contentEdit.getText().toString());
double money = Double.parseDouble(moneyEdit.getText().toString());
toModifyRecord.setMoney(isIncome?(money):(money*-1));
toModifyRecord.setStatus(((toModifyRecord.getStatus()==0)?(3):(1)));
toModifyRecord.setDate(date);
toModifyRecord.setDateString(dateString);
saveSuccess = toModifyRecord.save();
Log.d(TAG, toModifyRecord.toString());
} else {
Record record = new Record();
record.setCategory((!TextUtils.isEmpty(categoryNameStr)?(categoryNameStr):("无")));
record.setContent((!TextUtils.isEmpty(contentStr)?(contentStr):("无")));
double money = Double.parseDouble(moneyEdit.getText().toString());
record.setMoney(isIncome?(money):(money*-1));
record.setStatus(1); //1代表未同步到服务器
record.setDate(date);
record.setUuid(UuidUtil.getUuid());
record.setDateString(dateString);
saveSuccess = record.save();
}
if (saveSuccess) {
ToastUtil.Pop("保存成功");
finish();
} else {
ToastUtil.Pop("保存失败");
}
break;
case R.id.back_to_main_:
finish();
break;
default:
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: //Toolbar上的返回按钮,finish当前Activity
finish();
break;
default:
}
return true;
}
/**
* 切换收入支出列表时,改变字体颜色,并清空categoryName
*/
private void changeMoneyEditColor() {
moneyEdit.setText("");
categoryName.setText("");
if (isIncome) {
moneyEdit.setTextColor(Color.GREEN);
} else {
moneyEdit.setTextColor(Color.RED);
}
}
private class CategoryAdapter extends RecyclerView.Adapter {
private List categories;
class ViewHolder extends RecyclerView.ViewHolder {
View categoryView;
ImageView categoryImage;
TextView categoryName;
public ViewHolder(View view) {
super(view);
categoryView = view;
categoryImage = view.findViewById(R.id.add_record_icon);
categoryName = view.findViewById(R.id.add_record_name);
}
}
public CategoryAdapter(List categories) {
this.categories = categories;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.add_record_category_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
holder.categoryView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
categoryName.setText(holder.categoryName.getText());
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Category category = categories.get(position);
holder.categoryImage.setImageResource(category.getImageId());
holder.categoryName.setText(category.getName());
}
@Override
public int getItemCount() {
return categories.size();
}
}
private class ViewPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return pagerList.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
RecyclerView recyclerView = pagerList.get(position);
container.addView(recyclerView);
return recyclerView;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View)object);
}
}
}
//同步数据
private void syncData() {
String ip = preferences.getString("ip","");
if (isUpload) { //上传
final List toUpgradeRecords = LitePal.where( "status > ?", "0").find(Record.class);
HttpUtil.uploadRecords(ip+Constant.UPLOAD_RECORDS, phoneNumber, toUpgradeRecords, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
showToast("服务器异常");
finish();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseBody = response.body().string();
ResultInfo resultInfo = JSONObject.parseObject(responseBody, ResultInfo.class);
if (resultInfo.isFlag()) {
for (Record record : toUpgradeRecords) {
if (record.getStatus() != 2) {
record.setStatus(0);
record.save();
} else {
record.delete();
}
}
showToast("同步成功");
finish();
} else {
showToast("同步失败");
finish();}}});
} else {//下载
String address = ip+Constant.DOWNLOAD_RECORDS + phoneNumber;
HttpUtil.sendOkHttpGetRequest(address, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
showToast("服务器异常");
finish();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseBody = response.body().string();
ResultInfo resultInfo = JSONObject.parseObject(responseBody, ResultInfo.class);
Log.d(TAG, "onResponse: "+resultInfo.getData().toString());
List recordsDownloadFormServer = JSONArray.parseArray(resultInfo.getData().toString(),Record. class);
if (resultInfo.isFlag()) {
for (Record record : recordsDownloadFormServer) {
try {
LitePal.where("uuid = ? ", record.getUuid()).find(Record.class).get(0);
} catch (Exception e) {
e.printStackTrace(); record.setDateString(ConvertUtils.dateToString(record.getDate()));
record.save();
}
}
showToast("下载成功");
}
finish();
}});}}
4.测试用例
4.1测试连接服务器
输入ip
输入数据:18.114.0.80
操作过程:点击保存
预测结果:保存成功
实际结果:保存成功
4.2测试注册
输入数据:13926996293、yyc、123456、123456
操作过程:输入数据|点击注册
预测结果:注册成功并将数据存入后台服务器数据库
实际结果:注册成功并将数据存入后台服务器数据库
图4.2 测试注册
4.3 测试登录
输入数据:13926996293、123456
操作过程:输入数据
预测结果:登录成功
图4.3 测试登录
4.4测试下载到本地
作过程:选择同步、选择上下载到
预测结果:下载成功
实际结果:下载成功
图4.4 测试下载到本地
4.5测试添加
输入数据:book、55
操作过程:点击加号、点击学习、选择日期、输入数据、点击确定
预测结果:保存成功
实际结果:保存成功
图4.5测试添加
4.6 测试修改
输入数据:120
操作过程:长按一个账单、点击修改、点击确定
预测结果:保存成功
实际结果:保存成功
图 4.6 测试修改
4.7 测试删除
操作过程:长按一个账单、点击删除、点击确定
预测结果:删除成功
实际结果:删除成功
图4.7 测试删除
4.8测试上传服务器
操作过程:选择同步、选择上传服务器
预测结果:同步成功并存入后台服务器数据库
实际结果:同步成功并存入后台服务器数据库
图4.8测试上传服务器
4.9 查看统计数据
操作过程:点击统计数据
预测结果:显示统计数据
实际结果:显示统计数据
图4.9 查看统计数据
5.项目及课程总结
通过本次实验我再次学习了spring、springboot及mybatis的使用。并通过老师的讲解与学习,成功的与android成功的通过okhttp链接和LitePal,完成了同步信息,修改表,删除表,添加表等功能。进一步了解了安卓开发。