订单页面的展示
一、后端处理
1.开发封装从数据库查询的订单数据的类:Order
public class Order {
private Long o_id;
private String u_id;
private Long meal_id;
private Integer o_num;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date o_date;
private String meal_desc;
private String meal_pic;
private Double meal_price;
public Long getO_id() {
return o_id;
}
public void setO_id(Long o_id) {
this.o_id = o_id;
}
public String getU_id() {
return u_id;
}
public void setU_id(String u_id) {
this.u_id = u_id;
}
public Long getMeal_id() {
return meal_id;
}
public void setMeal_id(Long meal_id) {
this.meal_id = meal_id;
}
public Integer getO_num() {
return o_num;
}
public void setO_num(Integer o_num) {
this.o_num = o_num;
}
public Date getO_date() {
return o_date;
}
public void setO_date(Date o_date) {
this.o_date = o_date;
}
public String getMeal_desc() {
return meal_desc;
}
public void setMeal_desc(String meal_desc) {
this.meal_desc = meal_desc;
}
public String getMeal_pic() {
return meal_pic;
}
public void setMeal_pic(String meal_pic) {
this.meal_pic = meal_pic;
}
public Double getMeal_price() {
return meal_price;
}
public void setMeal_price(Double meal_price) {
this.meal_price = meal_price;
}
}
这个类包含了订单的一些基本信息,以及对应的getter和setter方法,用于获取和设置这些信息,这是一个标准的Java Bean模式,允许外部代码通过这些方法来访问和修改订单对象的状态。
2.开发封装符合页面展示结构的订单数据类:OrderVo
public class OrderVo {
private Date o_date;
private List<Order> list = new ArrayList<>();
public double getPrice() {
double price = 0;
for (Order order : list) {
price += order.getMeal_price() * order.getO_num();
}
return price;
}
public int getNum() {
int num = 0;
for (Order order : list) {
num += order.getO_num();
}
return num;
}
public Date getO_date() {
return o_date;
}
public void setO_date(Date o_date) {
this.o_date = o_date;
}
public List<Order> getList() {
return list;
}
public void setList(List<Order> list) {
this.list = list;
}
}
这个类是Order类的扩展,用于表示一个订单视图,是一个视图对象,它包含了订单的日期、一个订单列表以及计算订单总价和总数量的方法。
其中有两个方法:
1. getPrice()
: 计算并返回所有订单项的总价。它通过遍历list中的每个Order对象,将每个订单项的价格(meal_price)乘以其数量(o_num),然后将所有结果累加得到总价。
2. getNum()
: 计算并返回所有订单项的总数量。它通过遍历list中的每个Order对象,将每个订单项的数量累加得到总数量。
3.开发订单处理Servlet类: OrderServlet
@WebServlet({
"/order/list"
})
public class OrderServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String path = req.getServletPath();
switch(path){
case"/order/list":
orderList(req,resp);
break;
}
}
private void orderList(HttpServletRequest req, HttpServletResponse resp) throws IOException {
User user =(User)req.getSession().getAttribute("CurrUser");
if(user==null){
MyWeb.printJson(resp, R.err("请先登录!"));
return;
}
String sql = "select o.*, m.meal_desc,m.meal_pic,m.meal_price from t_order o join t_meal m on o.meal_id = m.meal_id where u_id = ? order by o_date desc";
List<Order> orderList = DaoCreater.currentDao().queryBeanList(Order.class,sql,user.getU_id());
List<OrderVo> orderVoList =new ArrayList<>();
OrderVo currVo =null;
for (Order order : orderList) {
if (currVo == null || !currVo.getO_date().equals(order.getO_date())){
currVo=new OrderVo();
currVo.setO_date(order.getO_date());
orderVoList.add(currVo);
}
currVo.getList().add(order);
}
MyWeb.printJson(resp,R.OK(orderVoList));
}
}
-
首先是注解:@WebServlet({“/order/list”}),这个注解用于指定Servlet的访问URL,即用户可以通过访问/order/list来触发这个Servlet。
-
doGet和doPost方法:这两个方法分别处理HTTP的GET和POST请求。在这个Servlet中,doGet方法直接调用了doPost方法,这意味着无论是GET还是POST请求,最终都会由doPost方法来处理。前面的servlet类中我们都是这样来处理HTTP请求的。
-
然后是doPost方法:这个方法根据请求的路径(通过req.getServletPath()获取)来决定执行哪个内部方法。在这个例子中,只有当路径为/order/list时,才会执行orderList方法。
-
最后是实现调用的orderList方法:
首先,它从会话(session)中获取当前用户(User对象),如果用户未登录(即user为null),则返回一个错误消息。
然后,它构建一个SQL查询语句,用于从数据库中检索与当前用户相关的订单信息,并将订单和菜品信息关联起来。
再使用DaoCreater.currentDao().queryBeanList(Order.class,sql,user.getU_id())
执行SQL查询,获取订单列表。
接下来,它遍历订单列表,将订单按日期分组,每组订单封装到一个OrderVo对象中。
最后,使用MyWeb.printJson(resp,R.OK(orderVoList))
将订单视图列表以JSON格式返回给客户端。
在这里这个Servlet的主要作用是提供一个接口,让前端可以获取当前用户的订单列表,并以一种结构化的方式(按日期分组)展示这些订单。这种方式有助于提高用户体验,使得订单信息更加清晰易懂。
最后关于这两个集合:
- orderList集合:
这是一个List类型的集合,用于存储从数据库查询得到的订单数据。
DaoCreater.currentDao().queryBeanList(Order.class,sql,user.getU_id())这行代码通过DAO(Data Access Object)模式从数据库中查询数据。Order.class指定了要查询的结果类型,sql是SQL查询语句,user.getU_id()是查询条件,用于获取当前用户的所有订单。
这个集合中的每个元素都是一个Order对象,包含了订单的详细信息,如订单ID、用户ID、菜品ID、订单数量、订单日期、菜品描述、菜品图片和菜品价格等。 - orderVoList集合:
这是一个List类型的集合,用于存储处理后的订单视图数据。
OrderVo是一个视图对象,它封装了订单的日期和订单列表,用于按日期组织订单数据。
new ArrayList<>();这行代码初始化了一个空的orderVoList集合。 - 处理逻辑:
OrderVo currVo = null;初始化一个OrderVo对象,用于临时存储当前处理的订单视图。
遍历orderList集合中的每个Order对象:
如果currVo是null(表示这是第一次遍历或者当前日期的订单已经处理完毕),或者当前订单的日期与currVo的日期不同时,会创建一个新的OrderVo对象,设置其日期,并将其添加到orderVoList集合中。
然后将当前遍历的Order对象添加到currVo的订单列表中。
这样,orderVoList集合中的每个OrderVo对象都包含了相同日期的所有订单。 - 返回结果:
MyWeb.printJson(resp,R.OK(orderVoList));这行代码将orderVoList集合以JSON格式返回给客户端。
R.OK(orderVoList)是一个封装了成功状态和数据的响应对象,表示请求处理成功,并将orderVoList作为响应数据。
后端完成,就该处理前端了。
二、前端处理
总体上是在订单页js部分开发获取订单数据函数,并调用执行就可以了。
在订单页依旧需要使用轻组件,如果已经导入可以跳过:
1.轻组件引入
<!--轻组件-->
<div class="toast-container position-fixed top-0 start-50 translate-middle-x mt
1">
<div id="toast" class="toast opacity-100 bg-white">
<div class="toast-header">
<strong class="me-auto"></strong>
<button type="button" class="btn-close" data-bs-dismiss="toast">
</button>
</div>
<div class="toast-body"></div>
</div>
</div>
导入后,将组件转换为对象使用,以及创建函数:
//创建轻组件对象
const toastObj = new bootstrap.Toast(document.querySelector(`#toast`), {delay: 2200});
const toast = (title = "信息", msg = "") => {
document.querySelector('#toast .me-auto').innerHTML = title;
document.querySelector('#toast .toast-body').innerHTML = msg;
toastObj.show();
}
前面解释过,这里就不解释了。
2. 开发获取订单数据函数
最后是开发获取订单数据函数:
const getList = async () => {
const resp = await fetch(`order/list`);
if (!resp.ok) return;
const result = await resp.json();
if (!result.success) {
toast("错误!", result.message);
console.log(result.message);
return;
}
const list = result.data;
const cartList = document.querySelector("#cartList");
let innerHTML = ``;
for (let i = 0; i < list.length; i++) {
const item = list[i];
innerHTML += `
<tr >
<td class="pt-5" colspan="5">
下单时间:${item.o_date}
<span class="px-2">数量:${item.num}</span>
总价:<span class="text-danger fs-3 ">¥${item.price}</span>
</td>
</tr>`;
for (let j = 0; j < item.list.length; j++) {
const o = item.list[j];
innerHTML += `
<tr>
<td class="p-3">
<img src="meal/pic?meal_pic=${o.meal_pic}" class="rounded" style="width:120px;" />
</td>
<td >
${o.meal_desc}
</td>
<td class=" fs-5 text-danger">
单价:¥${o.meal_price}
</td>
<td class="">
数量:${o.o_num}
</td>
</tr>`;
innerHTML+=`</tr>`;
}
}
cartList.innerHTML = innerHTML;
}
getList();
这段前端的代码主要分为一下几个步骤:
- 异步函数定义:
const getList = async () => { ... }
:使用async关键字定义了一个异步函数,允许在函数内部使用await关键字。 - 发起HTTP请求:
const resp = await fetch(order/list);
:使用fetch函数向服务器发送一个GET请求,请求的URL是order/list。await关键字用于等待请求完成并获取响应对象。 - 检查响应状态:
if (!resp.ok) return;
:检查响应对象的ok属性,如果请求不成功(即ok为false),则直接返回,不执行后续代码。 - 解析响应数据:
const result = await resp.json();
:将响应体解析为JSON格式的数据,并将其存储在result变量中。 - 检查数据成功状态:
if (!result.success) { ... }
:检查result对象的success属性,如果请求不成功(即success为false),则显示错误信息并返回。 - 获取订单列表数据:
`const list = result.data;``:从result对象中获取订单列表数据。 - 获取页面元素:
const cartList = document.querySelector("#cartList");
:使用querySelector方法获取页面上ID为cartList的元素,这个元素通常是一个表格或列表,用于显示订单数据。 - 构建HTML内容:
let innerHTML = ``;
:初始化一个变量innerHTML,用于存储构建的HTML内容。
遍历list数组,对于每个订单视图对象(item),构建一个表格行(),显示下单时间和订单信息。
再次遍历item.list数组,对于每个订单对象(o),构建另一个表格行,显示菜品图片、描述、单价和数量。 - 设置页面元素内容:
cartList.innerHTML = innerHTML;
:将构建好的HTML内容设置为cartList元素的innerHTML,从而在页面上显示订单数据。 - 错误处理:
toast("错误!", result.message);
:使用toast函数显示错误信息。
console.log(result.message);
:在控制台输出错误信息。
最后这段代码的主要作用是:
- 从服务器获取订单列表数据。
- 将数据解析并构建成HTML内容。
- 将HTML内容显示在页面上。