目 录
一、设计背景
1. 需求分析
2. 课题研究的目的和意义
二、系统需求分析与开发环境
1. 系统功能需求
2. 系统界面需求
3. 开发环境
三、系统设计
四、系统测试
1. 脑模拟器测试
五、总结与展望
六、重要程序
1. LoginActivity
2. RegisterActivity
3. PersonalCenterActivity
4. AllCommodityAdapter
- 设计背景
- 需求分析
如今的大学校园中随着大学生的购买能力的提高存在着两种局面。一是大学期间购买的收纳类、实用类物品,在毕业季大家面临带不走、不舍得扔的尴尬局面;二是购买的东西中越来越多的大家用不上的物品,这些物品成了大部分大学生的累赘。因此,低价卖掉这些仍可以继续利用的物品是一个两全其美的方法于是校园二手交易市场诞生了。目前,二手商品交易成为了当代大学生课余生活大热门。以我校为例,每年都要举办红红火火的跳蚤市场(如大四毕业时庞大的物品展卖),可见大学生对二手商品交易的需求,然而由于信息交流的落后,很多只限于校园公告栏或者请人代为宣传的方式进行交易。这种方式有很多局限性和偶然性,远远无法满足广大学子交易的需求。
建立一个校园二手交易平台可以大大方便在校的学生,方便了同学也营造了节约光荣,浪费可耻的校园文化氛围。最主要的是,它也可以通过网络将自己不用的东西放在网上,也可在网上找到自己需要的东西,物美价廉,达到双靡。
系统完成的主要功能有:用户设置功能、发布信息功能、信息管理功能、搜索信息功能,留言功能,及系统管理功能,具体业务功能包括如下:
用户注册:学生可利用自已学号进行注册,注册实现实名制。
用户登录:只有登录用户才能进行信息发布。管理员登录后可以进行系统管理。
发布信息:普通用户和管理员登录后都可以发布信息。
修改信息:普通用户可以修改自己发布的信息,管理员可以修改所有信息。
删除信息:普通用户可以删除自己发布的信息,管理员可以删除所有信息。
浏览信息:游客、普通用户和管理员可以浏览所有发布的信息。
搜索信息:游客、普通用户和管理员可以用关键字搜索所有发布的信息。普通用户可以搜索自己发布的所有信息。
发表留言:普通用户和管理员登录后都可以对发布信息进行留言。
查看留言:游客、普通用户和管理员都可以查看发布信息的留言。
删除留言:管理员可以删除留言。
添加二手指南:管理员可以添加二手指南。
查看二手指南:游客、普通用户和管理员都可以查看二手指南。
修改二手指南:管理员可以修改二手指南。
删除二手指南:管理员可以删除二手指南。
- 课题研究的目的和意义
校园二手交易网为用户提供了一个二手交易的平台。根据大中学校商品情况及学生的实际需求,系统的主要功能模块为信息分类、信息搜索、发布信息、用户注册登陆等。系统可提供用户对自己发表的供求信息的删除,以及对用户信息的修改功能,可以方便用户对自己基本信息的管理。
建设一个校园二手用品交易软件, 就是开发一个主要面向大学生的需求的二手用品交易平台,方便大学生足不出户就可以浏览想要的物品,方便大家信息交流,提高交易水平。为在校学生提供一个高效、便利、规范的二手交易市场。同时对二手商品循环使用可以倡导资源的合理使用,构建和谐校园、节约型校园, 减少浪费,给予货物第二次生命。
- 系统需求分析与开发环境
- 系统功能需求
随着科技的迅速发展校园二手商品交易市场也不仅仅局限于校园内摆地摊的形式,大家更多的是使用手机线上购物,我们的项目就是基于这样的局面产生的,让同学们足不出户就可以淘到自己所需要的物美价廉的物品。
校园二手淘项目需要包含登入注册功能,用户名和密码储存在Sharedpreferences轻型数据类中,按钮实现页面跳转。包括数据库的增删查改功能,采用的是SQLite数据库。
发布及查看二手商品信息阶段: 包括商品信息发布、 信息查看和信息留言等。商品信息按类别分类。发布人可以管理自已发布的信息,发布人有权对自己已发布信息进行修改、删除等操作。
- 系统界面需求
系统界面美观简洁,注册和登入的页面参考了许多app,要让页面做到简介美观,所以登入页面主页面都用到了自定义按钮样式和自定义输入框样式,按钮设计出颜色渐变的样式并加入圆角看起来不生硬,输入框同样加入了圆角的设计。
- 开发环境
Android studio 4.0.2+JDK1.8+gradle-6.1.1-all.zip
4. MVC 简介
模型-视图-控告器(MVC)是20世纪80年代Smalltalk-80出的一种软件模式,现在已经被广泛使用。
- 模型(Model)
模型是应用程序的主体部分。模型表示业务数据,或者业务逻辑。
- 视图(View)
视图是应用程序中用户界面相关的部分,是用户看到并与之交互的界面。
- 控制器(Controller)
控制器的工作就是根据用户的输入,控制用户界面显示和更新模型对象的状态。典型的MVC模式所包含的模块、每个模块的功能以及模块之间的关系如图2-1所示[2]:
图2-1 MVC组件的关系和功能
MVC模式的出现不仅实现的功能模块和显示模块的分离,同是赛马场还提高了应用系统的可维护性、可扩展性、可移植性和组件的可利用性。
在早期的程序中,如果不注意对数功能和显示的解耦合,常常估导致程序的复杂及难以维护,像VB,Delphi等RAD程序都有这种问题。甚至现在有C#,Java有时候也会出现把业务逻辑写在显示模块中的现象。
尽管MVC设计模式很早的提出了,但在Web项目的开发中引入MVC却是步履艰难。主要原因是在早期的Web项目开发中,程序语言和Html的分离一直难以实现,CGI程序以字条串输出的形式动态的生成html内容。直到基于J2EE的JSP Model2问世时才得以改观。它用JSP技术实现视图的功能,用Servlet技术实现控制器的功能,用JavaBean实现模型的功能。JSP Model2 结构如图2-2所示:
在Model 2这种框架结构中,Servlet作为控制器负责处理用户的请求以及创建JSP页面中所有要使用的Bean对象,并且还要根据用户的请求来返回到不同的JSP页面。
在使用Model 2开发框架时,一定要保证在JSP页面中不能包含任何的业务处理逻辑。它只是简单地得到对象或者在Servlet中创建的Bean,然后通过这些动态的内容来生成动态显示的页面。
Struts 本质上就是在Model 2的基础上实现一个MVC架构,它只有一个中心控制器,采用定制转向的URL并采用Action来处理逻辑。
5.系统功能模块设计
系统主要设计了用户设置功能、发布信息功能、信息管理功能、搜索信息功能,留言功能,及系统管理功能模块。
用户设置功能主要是用户注册必须填写所要求的个人资料,完成个人资料登入。
发布信息功能主要是为已注册用户的服务,登陆的用户可以即时发布自己的二手书商品信息,立刻就能浏览到。这是本系统的主要功能。
信息管理功能是帮助已发表信息的的用户管理自身发布的二手书商品信息的同时也管理短消息信息。此项功能也主要是服务于注册用户。
搜索信息功能是面向所有登陆到本系统的人员的,采用模糊查询的方法,遍历所有二手商品信息,搜索出浏览者感兴趣的内容。
留言功能是对某一二手书商品信息进行留言,还可以查看该信息的其他留言。
系统管理功能是系统管理员对系统所有信息资源进行统一管理的一个模块。系统功能结构如图3-2所示:
图 3-2 系统功能结构图
- 数据库结构
数据库需求分析
对于数据库的需求主要体现在对数据库的提交信息、更新信息、删除信息、保存信息等。这些信息的存在都取决于各个功能模块的对信息的需求。通过对功能模块的具体操作,实现对数据库中信息的输入和输出。所以,针对各个功能模块的需求,设计如下的数据表和数据结构:
- Maste 类表:用于实现平台用户我实名制及平台基本信息:
学院信息:包括学院编号,学院名,描述等。
班级信息:包括班级编号,班级名,学院编号,描述等。
学生信息:包括学号,姓名,班级编号,学院编号等。
类型信息:包括类型编号,类型名,类型描述等。
交易地区信息:包括地区编号,地区名,地区描述等。
- Temp 类表:用于实现平台各模块:
用户信息:包括用户编号、用户名、密码、学号,及用户的其它相关信息等。
商品信息:商品编号、信息标题、信息内容,发布信息的用户,信息相关内容等。
商品留言信息:包括留言编号、商品信息编号、留言内容等。
数据库概念结构设计
概念模型是对于信息世界的建模,是现实世界到信息世界的抽象,是数据库设计人员和用户之间进行交流的语言。它具有简洁明晰、易于理解和修改、便于向各种数据模型转换,从而生成相应的逻辑模式。
概念设计的目的是要确定系统的概念模型,因为概念模型是数据库系统的核心和基础,所以概念设计是数据库设计的关键。
数据库逻辑表设计
数据库逻辑模型
表3-7 用户表(t_user)
字段名 | 数据类型 | 约束条件 | 说明 |
ID | VARCHAR(50) | Primary Key | 用户编号 |
USERNAME | VARCHAR(10) | UNIQUE | 用户名 |
PASSWORD | varchar(100) | NOT NULL | 用户密码 |
STU_ID | VARCHAR(50) | Foreign Key | 学号 |
BIRTHDAY | DATETIME | NOT NULL | 生日 |
PHOTO | SMALLINT(5) | NOT NULL | 照片 |
QUESTION | VARCHAR(100) | NOT NULL | 注册问题 |
ANSWER | VARCHAR(100) | NOT NULL | 注册答案 |
| VARCHAR(50) | --- | |
| VARCHAR(20) | --- | |
CREATE_TIME | DATETIME | NOT NULL | 注册时间 |
STATUS | TINYINT(3) | NOT NULL | 状态 |
ROLE | TINYINT(3) | NOT NULL | 权限 |
表3-8 商品信息表(t_message)
字段名 | 数据类型 | 约束条件 | 说明 |
ID | VARCHAR(50) | Primary Key | 信息编号 |
MESSAGE_TITLE | VARCHAR(50) | UNIQUE | 信息标题 |
TYPE_ID | VARCHAR(50) | Foreign Key | 信息类型 |
AREA_ID | VARCHAR(50) | Foreign Key | 交易地区 |
OLD_VALUE | SMALLINT(5) | NOT NULL | 新旧值 |
PRICE | DECIMAL(10,0) | NOT NULL | 商品价格 |
R_USER | VARCHAR(10) | NOT NULL | 联系人 |
R_PHONE | VARCHAR(50) | NOT NULL | 联系电话 |
R_EMAIL | VARCHAR(50) | --- | |
MESSAGE_DESC | VARCHAR(200) | NOT NULL | 信息详情 |
MESSAGE_PHOTO | VARCHAR(50) | --- | 信息图片 |
CREATE_TIME | DATETIME | NOT NULL | 新增日期 |
FLAG | TINYINT(3) | NOT NULL | 信息标志 |
TOP_VALUE | INTEGER | NOT NULL | 人气值 |
CREATE_USER_ID | VARCHAR(50) | Foreign Key | 发布用户 |
- 系统设计
登入注册页面制作完后,做了一个导航页面,页面可以选择进入相应的功能模块,进入基础信息模块可以进行发布闲置、查看不同分类下的产品、进入个人中心等。商品基础信息页面加入了增删查改的功能,采用的是SQlite数据库,方便用户对商品编辑修改。页面的设计同样采用了按钮的自定义样式和输入框的自定义样式。页面个人中心模块头像部分设计了一个图片样式的自定义,给图片添加了一个边框,使页面看起来和谐统一美观。
- 系统测试
- 脑模拟器测试
- 重要程序
- LoginActivity
public class LoginActivity extends AppCompatActivity {
EditText EtStuNumber,EtStuPwd;
private String username;
LinkedList<User> users = new LinkedList<>();
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
TextView tvRegister = findViewById(R.id.tv_register);
//跳转到注册界面
tvRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(LoginActivity.this,RegisterActivity.class);
startActivity(intent);
}
});
EtStuNumber = findViewById(R.id.et_username);
EtStuPwd = findViewById(R.id.et_password);
Button btnLogin = findViewById(R.id.btn_login);
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean flag = false;
if(CheckInput()) {
UserDbHelper dbHelper = new UserDbHelper(getApplicationContext(),UserDbHelper.DB_NAME,null,1);
users = dbHelper.readUsers();
for(User user : users) {
//如果可以找到,则输出登录成功,并跳转到主界面
if(user.getUsername().equals(EtStuNumber.getText().toString()) && user.getPassword().equals(EtStuPwd.getText().toString()) ) {
flag = true;
Toast.makeText(LoginActivity.this,"恭喜你登录成功!",Toast.LENGTH_SHORT).show();
Intent intent = new Intent(LoginActivity.this,MainActivity.class);
Bundle bundle = new Bundle();
username = EtStuNumber.getText().toString();
bundle.putString("username",username);
intent.putExtras(bundle);
startActivity(intent);
}
}
//否则提示登录失败,需要重新输入
if (!flag) {
Toast.makeText(LoginActivity.this,"学号或密码输入错误!",Toast.LENGTH_SHORT).show();
}
}
}
});
}
//检查输入是否符合要求
public boolean CheckInput() {
String StuNumber = EtStuNumber.getText().toString();
String StuPwd = EtStuPwd.getText().toString();
if(StuNumber.trim().equals("")) {
Toast.makeText(LoginActivity.this,"学号不能为空!",Toast.LENGTH_SHORT).show();
return false;
}
if(StuPwd.trim().equals("")) {
Toast.makeText(LoginActivity.this,"密码不能为空!",Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
}
- RegisterActivity
public class RegisterActivity extends AppCompatActivity {
EditText tvStuNumber,tvStuPwd,tvStuConfirmPwd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
Button btnCancel = findViewById(R.id.btn_cancel);
//返回到登录界面
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
tvStuNumber = findViewById(R.id.et_username);
tvStuPwd = findViewById(R.id.et_password);
tvStuConfirmPwd = findViewById(R.id.et_confirm_password);
//注册点击事件
Button btnRegister = findViewById(R.id.btn_register);
btnRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//首先确保不为空
if(CheckInput()) {
User user = new User();
user.setUsername(tvStuNumber.getText().toString());
user.setPassword(tvStuPwd.getText().toString());
UserDbHelper dbHelper = new UserDbHelper(getApplicationContext(),UserDbHelper.DB_NAME,null,1);
dbHelper.addUser(user);
Toast.makeText(RegisterActivity.this,"恭喜你注册成功!",Toast.LENGTH_SHORT).show();
//销毁当前界面
finish();
}
}
});
}
//判断输入是否符合规范
public boolean CheckInput() {
String username = tvStuNumber.getText().toString();
String password = tvStuPwd.getText().toString();
String confirm_password = tvStuConfirmPwd.getText().toString();
if(username.trim().equals("")) {
Toast.makeText(RegisterActivity.this,"用户名不能为空!",Toast.LENGTH_SHORT).show();
return false;
}
if(password.trim().equals("")) {
Toast.makeText(RegisterActivity.this,"密码不能为空!",Toast.LENGTH_SHORT).show();
return false;
}
if(confirm_password.trim().equals("")) {
Toast.makeText(RegisterActivity.this,"确认密码不能为空!",Toast.LENGTH_SHORT).show();
return false;
}
if(!password.trim().equals(confirm_password.trim())) {
Toast.makeText(RegisterActivity.this,"两次密码输入不一致!",Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
}
- PersonalCenterActivity
public class PersonalCenterActivity extends AppCompatActivity {
TextView TvStuNumber;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_personal_center);
//取出登录时的登录名
TvStuNumber = findViewById(R.id.tv_student_number);
String StuNumber = this.getIntent().getStringExtra("username1");
TvStuNumber.setText(StuNumber);
//返回主界面
Button btnBack = findViewById(R.id.btn_back);
btnBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
//点击修改密码按钮
final Button btnModifyPwd = findViewById(R.id.btn_modify_password);
btnModifyPwd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(),ModifyPwdActivity.class);
Bundle bundle = new Bundle();
bundle.putString("stu_number",TvStuNumber.getText().toString());
intent.putExtras(bundle);
startActivity(intent);
}
});
//点击查看我的发布按钮
Button btnMyGoods = findViewById(R.id.btn_my_goods);
btnMyGoods.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(),MyCommodityActivity.class);
Bundle bundle = new Bundle();
bundle.putString("stu_id",TvStuNumber.getText().toString());
intent.putExtras(bundle);
startActivity(intent);
}
});
//点击查看我的收藏按钮
Button btnMyCollection = findViewById(R.id.btn_my_collection);
btnMyCollection.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(),MyCollectionActivity.class);
Bundle bundle = new Bundle();
bundle.putString("stuId",TvStuNumber.getText().toString());
intent.putExtras(bundle);
startActivity(intent);
}
});
//点击个人信息按钮
Button btnUserInfo = findViewById(R.id.btn_user_info);
btnUserInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(),MyInfoActivity.class);
Bundle bundle = new Bundle();
bundle.putString("stu_number1",TvStuNumber.getText().toString());
intent.putExtras(bundle);
startActivity(intent);
}
});
//退出登录按钮点击事件
Button btnLogOut = findViewById(R.id.btn_logout);
btnLogOut.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(PersonalCenterActivity.this);
builder.setTitle("提示:").setMessage("确认退出系统吗?").setIcon(R.drawable.icon_user).setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
//跳转到登录界面
Intent intent = new Intent(getApplicationContext(),LoginActivity.class);
startActivity(intent);
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
}
});
}
}
- AllCommodityAdapter
public class AllCommodityAdapter extends BaseAdapter {
private Context context;
private LayoutInflater layoutInflater;
private List<Commodity> commodities = new ArrayList<>();
//对每一个item保存其位置
HashMap<Integer,View> location = new HashMap<>();
public AllCommodityAdapter(Context context) {
this.context = context;
layoutInflater = LayoutInflater.from(context);
}
public void setData(List<Commodity> commodities) {
this.commodities = commodities;
notifyDataSetChanged();
}
@Override
public int getCount() {
return commodities.size();
}
@Override
public Object getItem(int position) {
return commodities.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(location.get(position) == null){
convertView = layoutInflater.inflate(R.layout.layout_all_commodity,null);
Commodity commodity = (Commodity) getItem(position);
holder = new ViewHolder(convertView,commodity);
//保存view的位置position
location.put(position,convertView);
convertView.setTag(holder);
}else{
convertView = location.get(position);
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
//定义静态类,包含每一个item的所有元素
static class ViewHolder {
ImageView ivCommodity;
TextView tvTitle,tvType,tvDescription,tvPrice;
public ViewHolder(View itemView,Commodity commodity) {
tvTitle = itemView.findViewById(R.id.tv_name);
tvType = itemView.findViewById(R.id.tv_type);
tvPrice = itemView.findViewById(R.id.tv_price);
tvDescription = itemView.findViewById(R.id.tv_description);
ivCommodity = itemView.findViewById(R.id.iv_commodity);
tvTitle.setText(commodity.getTitle());
tvDescription.setText(commodity.getDescription());
tvPrice.setText(String.valueOf(commodity.getPrice())+"元");
tvType.setText(commodity.getCategory());
byte[] picture = commodity.getPicture();
//从字节数组中解码生成不可变的位图
//public static Bitmap decodeByteArray(byte[] data, int offset, int length)
Bitmap img = BitmapFactory.decodeByteArray(picture,0,picture.length);
ivCommodity.setImageBitmap(img);
}
}