本篇博客是基于Javaweb和web前端完成的一个奶茶店后台管理系统。
一、项目概述(总体设计)
1.系统框架图
奶茶店后台管理系统主要分为七个模块(页面),分别是:登录、奶茶菜单、用户管理、订单信息、公告通知、用户评论、门店信息。系统的总体框架图如下:
2.总体流程
管理员首先进行登录操作,进入系统页面。可以选择不同的页面,分别对奶茶、用户、评论、订单、门店、公告这七个实体类进行增删改查的操作。
二、功能详情
后台管理系统功能主要是对数据库的操作,即:增删改查;
需考虑功能的合理性,后台管理系统是面向管理人员的,而非用户。
分类 | 子模块 | 功能描述 |
奶茶菜单 | 添加奶茶种类 | 点击添加按钮,输入奶茶基本信息,点击确定添加 |
删除已有的奶茶 | 点击删除按钮,删除对应已有的奶茶 | |
修改奶茶信息 | 点击修改按钮,修改对应奶茶的基本信息 | |
查找奶茶信息 | 输入奶茶的名称,或选择分类,即可模糊搜素所有奶茶 | |
用户菜单 | 修改用户 | 点击修改按钮,修改对应的用户基本信息 |
删除用户 | 点击删除按钮,删除对应已有的用户 | |
公告菜单 | 修改公告 | 点击修改按钮,修改对应的公告基本信息 |
删除公告 | 点击删除按钮,删除对应已有的用户 | |
查看公告 | 输入关键词,或选择分类,即可模糊搜素所有有关公告信息 | |
订单菜单 | 修改订单状态 | 点击对应状态按钮,修改对应的订单状态 |
删除订单 | 点击删除按钮,删除对应已有的订单 | |
查看订单 | 输入用户名关键字,或选择状态分类,即可模糊搜素所有有关订单信息 | |
用户评论菜单 | 回复评论 | 点击编辑按钮。输入回复内容,点击保存即可完成评论回复 |
删除评论 | 点击删除按钮,删除对应已有的评论 | |
查找评论 | 输入奶茶名称关键字,即可模糊搜素所有有关订单信息 | |
门店菜单 | 查找门店 | 输入门店名称关键字,即可模糊搜素所有有关门店信息 |
删除门店 | 点击删除按钮,删除对应已有的门店 |
三、概要设计
1.关系模式(7个实体类)
奶茶(奶茶编号,奶茶名,价格,介绍,分类)
用户(用户编号,姓名,性别,年龄,联系电话)
管理员(管理员编号,姓名,密码)
公告(公告编号,标题,发布时间,发布内容,发布类型)
评论(评论编号,奶茶名,用户名,评论内容,回复内容,状态,创建时间,门店名称,门店编号,用户编号)
订单(订单编号,下单时间,用户名,联系电话,内容,状态,用户编号)
门店(门店编号,门店名称,地址,门店号码,城市名,区域名)
2.整体E-R图
管理员可以管理所有信息。一个管理员可以管理多个用户、门店、公告、奶茶、评论、订单,同一个用户、订单等可以被多个管理员管理(即进行增删改查的操作),是多对多的关系。
四、详细设计
1.物理表设计
user用户表
字段名 | 类型 | 长度 | 允许空(Y/N) | 字段意义 |
user_id | int | 10 | N | 主键,用户id |
username | varchar | 255 | N | 用户名 |
sex | tinyint | 1 | N | 性别 |
age | varchar | 3 | N | 年龄 |
phone | varchar | 64 | N | 联系电话 |
admin管理员表
字段名 | 类型 | 长度 | 允许空(Y/N) | 字段意义 |
id | int | 10 | N | 主键,管理员id |
username | varchar | 32 | N | 管理员姓名 |
password | varchar | 64 | N | 管理员密码 |
announcement公告表
字段名 | 类型 | 长度 | 允许空(Y/N) | 字段意义 |
id | int | 10 | N | 主键,公告id |
title | varchar | 255 | N | 公告标题 |
time | varchar | 255 | N | 公告时间 |
content | varchar | 255 | N | 公告内容 |
type | tinyint | 1 | N | 公告类型 |
comment评论表
字段名 | 类型 | 长度 | 允许空(Y/N) | 字段意义 |
id | int | 10 | N | 主键,评论id |
milktea_name | varchar | 30 | N | 奶茶名称 |
username | varchar | 255 | N | 用户名 |
content | varchar | 255 | N | 评论内容 |
content | varchar | 255 | Y | 回复内容 |
status | int | 10 | N | 状态: 0:已回复 1:未回复 |
create_time | varchar | 255 | N | 创建时间 |
shop | Varchar | 255 | N | 门店名称 |
shop_id | int | 10 | N | 外键,门户id (引用shop表) |
user_id | int | 10 | N | 外键,用户id (引用user表) |
milktea奶茶表
字段名 | 类型 | 长度 | 允许空(Y/N) | 字段意义 |
id | int | 10 | N | 主键,奶茶id |
name | varchar | 30 | N | 奶茶名字 |
price | int | 10 | N | 价格 |
intro | varchar | 255 | N | 介绍 |
classify | tinyint | 1 | N | 分类: 0:奶茶 1:奶绿 2:咖啡 3:果茶 4:不含茶 |
order订单表
字段名 | 类型 | 长度 | 允许空(Y/N) | 字段意义 |
oid | int | 10 | N | 主键,订单id |
order_date | varchar | 20 | N | 下单时间 |
username | varchar | 255 | N | 用户名 |
phone | varchar | 64 | N | 联系电话 |
content | varchar | 255 | N | 订单内容 |
status | tinyint | 1 | N | 订单状态: 0:未接单 1:已接单 2:已完成 |
user_id | int | 10 | N | 外键,用户id (引用user表) |
shop门店表
字段名 | 类型 | 长度 | 允许空(Y/N) | 字段意义 |
id | int | 10 | N | 主键,门店id |
shopname | varchar | 255 | N | 门店名称 |
address | varchar | 255 | N | 地址 |
number | varchar | 255 | N | 门店号码 |
city | varchar | 255 | N | 城市名 |
block | varchar | 255 | N | 区域名 |
按照设计的7个物理表,在navicat中创建数据库milktea,并填上数据,自行发挥即可
对应7个页面模块:登录页面、奶茶菜单页面、用户页面、评论页面。。。其中有增、改功能的页面还包括填写修改信息的新页面
在设计数据库的时候为了实现对数据的管理,一个实体类需要不同的属性,但并不是所有现实中有的属性有需要写上去。比如门店实体类中,还可以有:管理员,但在这个页面中我们已经可以通过“城市、区域、名称”3个属性对门店进行模糊搜索,所以再多的属性也是重复的效果,就没有再写。
包括设计页面的时候,我也考虑过做更多内容,比如值班表页面(按姓名、门店、日期查找值班信息),工作人员意见收集页面(功能类似于用户评论了),最后选择的页面都是在逻辑上可以实现至少两种操作的,单一功能的页面用处也就不大了。
2.数据模型设计
五、编程开发
做完设计才可以开始写代码。写代码要养成好的习惯,一定要写注释,一定要写注释,一定要写注释!
环境:Tomcat 9.0.202
数据库连接:c3p0
/*环境配置会另写一篇*/
导入需要的jar包,在c3p0-config.xml文件中连接milktea数据库
项目整体结构:
bean层:封装实体类,含有私有变量和修改它们的公共方法
vo文件夹存放有外键关联的两个实体类组成的新类
dao层:数据访问层,存放具体方法(增删改查),和数据库进行交互
service层:业务逻辑层,含有接口和抽象类(个人理解就是:使用dao层中的方法)
servlet层:表现层,负责接收并处理用户请求,调用Service层处理业务逻辑,最后将结果返还给用户
web.admin中为jsp文件,编写页面样式
在修改css时大概率会出现无变化的情况
解决方法:行末尾加上!important是最快的方法
页面跳转:href使用在servlet层中 @WebServerlet 里我们给页面起的名字,一一对应
将数据库中的数据传到页面:
首先确保c3p0-config.xml文件内信息正确,然后在jsp文件中找到需要数据显示的地方,使用c:forEach c:if标签传输数据
<tbody id="tb_order">
<c:forEach items="${requestScope.orderList}" var="orderList">
<tr>
<td>${orderList.order.oid}</td>
<td>${orderList.order.order_date}</td>
<td>${orderList.order.username}</td>
<td>${orderList.order.phone}</td>
<td>${orderList.order.content}</td>
<c:if test="${orderList.order.status ==0}">
<td>未接单</td>
</c:if>
<c:if test="${orderList.order.status ==1}">
<td>已接单</td>
</c:if>
<c:if test="${orderList.order.status ==2}">
<td>已完成</td>
</c:if>
<td>
<button class="btn btn-warning btn-sm waves-effect waves-light m-b-5"
onclick="edit(${orderList.order.oid},${orderList.order.status})">接单
</button>
<button class="btn btn-primary btn-sm waves-effect waves-light m-b-5"
onclick="edit2(${orderList.order.oid},${orderList.order.status})">完成
</button>
<button class="btn btn-danger btn-sm waves-effect waves-light m-b-5"
onclick="del(${orderList.order.oid})">删除
</button>
</td>
</tr>
</c:forEach>
</tbody>
jsp文件中编写保存奶茶的方法:容易出错,注意url链接和传输的data
<script>
// 保存奶茶
function subMilkTea() {
// 获取参数
var name = $("#milktea_name").val();
var price =$("#milktea_price").val();
var intro = $("#milktea_intro").val()
var classify0 = $("#classify0").prop("checked");
var classify1 = $("#classify1").prop("checked");
var classify2 = $("#classify2").prop("checked");
var classify3 = $("#classify3").prop("checked");
var classify4 = $("#classify4").prop("checked");
var classify;
if(classify0){
classify = 0;
}
if(classify1){
classify = 1;
}
if(classify2){
classify = 2;
}
if(classify3){
classify = 3;
}
if(classify4){
classify = 4;
}
// 发起ajax请求
$.ajax({
url: "/admin/milktea/create",
data: {
name,
price,
intro,
classify
},
type: "POST",
dataType: "json",
success: function (result) {
console.log("result:"+result)
if (result.code === 200) {
location.href = "/admin/editMilkTea"
}
}
})
}
</script>
六、项目展示
项目内容
登录:
登录成功进入系统,首页是奶茶菜单页:
添加新奶茶:
用户:
订单:
公告:
点击编辑新增公告:
评论:
回复评论:
门店:
ps:搜索功能--模糊搜素
模糊搜索的实现是通过修改sql语句,并且可以多条件搜索,如奶茶菜单的搜索功能:
milkTeaListDao:
public class MilkTeaListDao {
// 获取所有奶茶
public static List<Milktea> queryAll() throws SQLException {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
String sql = "SELECT * FROM milktea";
return qr.query(sql,new BeanListHandler<>(Milktea.class));
}
// 根据名称、分类查询奶茶信息
public static List<Milktea> searchByNameAndClassify(String name,String classify) throws SQLException {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
List<String> list = new ArrayList<>();
String sql = "SELECT * FROM milktea WHERE 1=1";
if(!name.equals("")){
sql += " AND name LIKE ?"; // 只添加占位符
// 构造一个包含%的字符串作为参数值
String param = "%" + name + "%";
list.add(param); // 将构造好的字符串添加到参数列表中
}
if(!classify.equals("")){
sql += " AND classify LIKE ?";
list.add(classify);
}
System.out.println(sql);
return qr.query(sql,new BeanListHandler<>(Milktea.class),list.toArray());
}
// 根据id删除奶茶
public static int delMilkTeaById(int id) throws SQLException {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
String sql = "DELETE FROM milktea WHERE id = ?;";
qr.update(sql,id);
return qr.update(sql,id);
}
}
JSP页面:
<form action="/admin/editMilkTea" method="post" id="cform" class="form-inline" role="form">
<div class="form-group">
<input type="text" class="form-control" id="name" name="name"
placeholder="请输入名称"/>
</div>
<div class="form-group">
<select class="select2 form-control" id="classify" name="classify"
data-placeholder="请选择种类...">
<option value="">请选择种类</option>
<option value="0">奶茶</option>
<option value="1">奶绿</option>
<option value="2">咖啡</option>
<option value="3">果茶</option>
<option value="4">不含茶</option>
</select>
</div>
<input id="search-btn" type="submit"
class="btn btn-sm btn-success" />
<span class="btn btn-sm btn-success" onclick="create()">新增奶茶</span>
</form>
搜索名字中有“C”且种类为“咖啡”的所有商品:
同理:搜索名字中有“张”且状态为“未接单”的订单
七、小结
一个页面中往往包含多个功能,作为后台管理系统,通常是对数据进行增删改查,对数据库数据表进行修改;
一个功能的实现需要在bean创建实体类,Dao层编写方法,service层获取数据,servlet编写doget,dopost才能最终实现,也需要在jsp页面中通过c标签获取数据;
作为一个逻辑和功能还算比较完整的管理系统项目,事实上作者写了很多很多的方法,类,接口,页面文件,过程中难免头昏眼花,遇到卡顿无从下手的情况,配置环境是第一步,是非常重要的一步;
在过程中,正确命名java文件,养成写注释的好习惯,以及学会通过控制台输出寻找问题位置都非常重要。从一开始有大致的方向,到系统的设计,一定要随时记录想法,在一遍遍思考中发现漏洞,或许突然冒出更好的想法,包括美化页面等等,让项目的逻辑、功能都更加完善。
希望这篇博客对您能有所帮助,欢迎大家提出宝贵建议ღ( ´・ᴗ・` )