SpringBoot + VUE实现订单案例

Vue是一个前端的双向绑定类的框架,使用它完成前端页面逻辑非常方便,按照其约定可以高效完成前端复杂业务逻辑,用户不必再关心数据正确回显问题,只要数据格式是正确的,配置双向绑定规则是正确的,系统就能正确显示页面。尤其在单网页应用中,用法最为方便。如下介绍如何快速使用VUE设计案例。

什么是双向绑定

Vue框架很核心的功能就是双向的数据绑定。 双向是指:HTML标签数据 绑定到 Vue对象,另外反方向数据也是绑定的。通俗点说就是,Vue对象的改变会直接影响到HTML的标签的变化,而且标签的变化也会反过来影响Vue对象的属性的变化。

在这里插入图片描述

开发步骤:

下载VUE

从官网下载

或从CDN下载

Staticfile CDN(国内) : https://cdn.staticfile.org/vue/2.2.2/vue.min.js
unpkg:https://unpkg.com/vue/dist/vue.js, 会保持和 npm 发布的最新的版本一致。
cdnjs : https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js

下载AXIOS

AXIOS是基于promise用于浏览器和node.js的http客户端

1、 利用npm安装npm install axios --save
2、 利用bower安装bower install axios --save
3、 直接利用cdn引入 https://unpkg.com/axios/dist/axios.min.js

SQL

create table t_order(order_id int auto_increment primary key,
	user_id varchar(100),payment int,payment_type int,
	order_status int,create_time datetime,payment_time datetime);
	
alter table t_order add province varchar(10);
alter table t_order add city varchar(10);
alter table t_order add county varchar(10);
	
create table t_orderitem(id int auto_increment primary key,
	item_id varchar(100),order_id int,item_num int,item_price int,
	total_fee int);
	
create table t_store(id int auto_increment primary key,
	item_id varchar(100),item_info varchar(200),item_price int,
	inventor_num int);


CREATE TABLE `t_address` (
  `code` varchar(255) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `t_address` VALUES ('130000','河北省'),('130100','石家庄市'),('130102','长安区'),('130104','桥东区'),('130105','新华区'),('320000','江苏省'),('320100','南京市'),('320102','玄武区'),('320103','白下区'),('320104','秦淮区');
	
1 耐克男运动鞋 789
2 女风衣  1688
3 《thinking in java》 78

insert into t_store(item_id,item_info,item_price,inventor_num)
	values(1,'耐克男运动鞋',789,10000);
insert into t_store(item_id,item_info,item_price,inventor_num)
	values(2,'女风衣 ',1688,10000);
insert into t_store(item_id,item_info,item_price,inventor_num)
	values(3,'《thinking in java》',78,10000);	

设计网页

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>订单列表</title>
<link rel="stylesheet" type="text/css" href="/js/base.css">
<script type="text/javascript" src="/js/jquery.min.js"></script>
<script type="text/javascript" src="/js/base.js"></script>
<script type="text/javascript" src="/js/vue.js"></script>
<script type="text/javascript" src="/js/axios.min.js"></script>
<script>
	//点击新增时,通过后台加载订单,调用VUE对象的loadorder方法
	//如果新增返回订单空对象,VUE根据数据绑定规则将对应数据显示在网页上
	function doadd()
	{
		app.loadorder('');
		//新增订单的DIV层取消显示
		$('#orderitemdiv').css('display','block');
	}
	//通过订单ID打开订单
	function openorder(id)
	{
		app.loadorder(id);
		//新增订单的DIV层显示,VUE根据数据绑定规则将对应数据显示在网页上
		$('#orderitemdiv').css('display','block');
	}
	//添加订单明细,这里只操作订单JS对象,VUE根据数据绑定规则将对应数据显示在网页上	
	function doadditem()
	{
		//添加订单明细项
		var oi={
				item_id:1,
				item_num:1,
				item_price:10,
				uuid:Math.random()//定义唯一uuid,用于前台页面删除此项订单明细
		}
		//向订单JS数据对象添加订单明细
		app.order.items.push(oi);
	}
	//通过订单明细UUID删除此时订单明细
	//这里只操作订单JS对象,VUE根据数据绑定规则将对应数据显示在网页上
	function dodelitem(uuid)
	{
		for(var i=0;i<app.order.items.length;i++)
		{
			var oi = app.order.items[i];
			if(uuid == oi.uuid)
			{
				//删除订单JS对象中明细集合中相应的元素
				//参考JS操作集合的方法splice
				//arrayObj.splice(start, deleteCount,[itemObj]...);
				app.order.items.splice(i,1);
			}
		}
	}
	//通过Ajax向后台保存订单JS数据对象
	function dosaveorder()
	{
		//var obj = JSON.stringify(app.order);
		//调用定义VUE对象中的保存方法,将当前订单JS对象提交到后台
		app.dosave();
	}
	//关闭订单明细DIV
	function doclose()
	{
		$('#orderitemdiv').css('display','none');
	}
</script>
</head>

<body>
	<div id="app">
		<input type="button" value="添加订单" onclick="doadd()"/>
		<table>
			<tr>
				<th>用户</th>
				<th>订单时间</th>
				<th>支付时间</th>
			</tr>
			<!-- 
				绑定VUE对象中数据对象list,循环显示到Table的Tr控件上,迭代对象命名为o
			-->
			<tr v-for="o in list">
				<!-- 如果VUE将数据拼接字符串必须使用+连接,不能使用{{}} -->
				<td><a v-bind:href="'javascript:openorder('+o.order_id+')'">{{ o.user_id }}</a></td>
				<!-- VUE使用{{}}绑定数据到DOM控件上,dateFormat上日期处理函数-->
				<td>{{ dateFormat(o.create_time) }}</td>
				<td>{{ dateFormat(o.payment_time) }}</td>
			</tr>
		</table>
		<!-- VUE绑定HTML代码片断使用 v-html,普通字符绑定使用v-bind,v-model -->
		<div class="pdiv" v-html="pagediv"></div>
		
		<div id="orderitemdiv" style="display:none">
			<h3>添加订单明细</h3>
			<form id="frm" name="frm" action="/saveitem">
			<input type="hidden" name="uuid" value=""/>
			<input type="button" value="添加商品" onclick="doadditem()"/>
			<input type="button" value="提交订单" onclick="dosaveorder()"/>
			<input type="button" value="关闭" onclick="doclose()"/>
			<table>
				<tr>
					<td>订单用户</td>
					<td>
					<!-- 绑定定义用户数据到输入控件 -->
					<input type="text" v-model="order.user_id">
					</td>
				</tr>
				<tr>
					<td>省份</td>
					<td>
					<!-- 绑定定义地址中省份数据到下拉列表框,绑定选中事件使用@,
						onProvinceSelected是VUE中用户自定义的方法-->
					<select id="province" name="province" v-model="order.province" 
						@change="onProvinceSelected">
						<!-- 循环显示各省份 -->
							<option v-for="c in order.provinceList" :value="c.code">{{c.name}}</option>
					</select>
					</td>
				</tr>
				<tr>
					<td>地区</td>
					<td>
					<select id="city" name="city" v-model="order.city"
						@change="onCitySelected">
					    <option v-for="c in order.cityList" :value="c.code" >{{c.name}}</option>
					</select>
					</td>
				</tr>
				<tr>
					<td>县市</td>
					<td>
					<select id="county" name="county" v-model="order.county">
						<option v-for="c in order.countyList" :value="c.code" >{{c.name}}</option>
					</select>
					</td>
				</tr>
			</table>
			<div id="itemdiv">
			<br>
			<h3>所选商品</h3>
				<table id="itemtab">
					<tr>
						<th>商品名称</th>
						<th>数量</th>
						<th>数量</th>
						<th>价格</th>
						<th>总计</th>
						<th>删除</th>
					</tr>
					<!-- 
						绑定VUE对象中订单数据对象order的明细,循环显示到Table的Tr控件上,迭代对象命名为oi
					-->
					<tr v-for="oi in order.items">
						<td>
						<select v-model="oi.item_id">
								<option v-for="c in productList" :value="c.code">{{c.name}}</option>
						</select>
						</td>
						<td>{{ oi.item_num }}</td>
						<td><input type="text" v-model="oi.item_num"/></td>
						<td>{{ oi.item_price }}</td>
						<td>{{ oi.item_price * oi.item_num}}</td>
						<td><input type="button" value="删除" v-bind:onclick="'dodelitem('+oi.uuid+')'"/></td>
					</tr>
		      </table>
			</div>
	
			</form>
		</div>
	</div>
	<script>
//定义VUE对象,加载数据并绑定到HTML DOM元素上
var app = new Vue({
	el: '#app',//VUE数据对象绑定DIV控件,el变量名称不可改变
	data: {//定义数据对象,data变量名称不可改变
		//所有自定义变量名称可以修改
		order:{},//自定义代表订单对象变量
		productList:[//自定义产品集合
			{"code":1,"name":"手机"},
			{"code":2,"name":"笔记本"},
			{"code":3,"name":"电脑"}
		],
		list:[],//每页显示记录集合
		page:1,//当前页面
		rows:4,//每页显示记录数
		pagediv:''//分页DIV HTML代码片段,这里使用JS前台分页技术
	},
	created: function(){//在VUE对象生命周期中,创建对象时调用
		this.dopageload();//调用自定义方法加载分页数据
	},
	methods:{//自定义函数
		dateFormat:function(time) {//处理日期时间函数
		    var date=new Date(time);
		    var year=date.getFullYear();
		    var month= date.getMonth()+1<10 ? "0"+(date.getMonth()+1) : date.getMonth()+1;
		    var day=date.getDate()<10 ? "0"+date.getDate() : date.getDate();
		    var hours=date.getHours()<10 ? "0"+date.getHours() : date.getHours();
		    var minutes=date.getMinutes()<10 ? "0"+date.getMinutes() : date.getMinutes();
		    var seconds=date.getSeconds()<10 ? "0"+date.getSeconds() : date.getSeconds();
		    return year+"-"+month+"-"+day+" "+hours+":"+minutes+":"+seconds;
		},
		loadorder:function(id)//根据订单ID装载订单数据对象
		{
			_this = this;
			axios.get('/findorder?id='+id)
			.then(function(res){
				_this.order = res.data;
			});
		},
		onProvinceSelected:function(){//选择省份时调用的方法
			console.log(this.order.province)
			_this = this;
			//当选中省份下拉框时,Ajax选中地区
			axios.get('/findcity?code='+_this.order.province)
				.then(function(res){
					//当选中地区下拉框时,Ajax选中县级市
					_this.order.cityList = res.data;
					_this.order.city = res.data[0].code;
					axios.get('/findcounty?code='+_this.order.city)
						.then(function(res2){
							_this.order.countyList = res2.data;
							_this.order.county = res2.data[0].code;
					});
			});

		},
		onCitySelected:function(){//选择地区时调用的方法
			console.log(this.order.province)
			_this = this;
			//当选选中地区下拉框时,Ajax选中县级市
			axios.get('/findcounty?code='+_this.order.city)
			.then(function(res2){
				_this.order.countyList = res2.data;
				_this.order.county = res2.data[0].code;
			});
		},
		dopageload:function(page,rows){//使用Ajax加载分页数据
			_this = this;
			if(page == null)
				page = 1;
			if(rows == null)
				rows = 4;
			//使用Ajax请求分页数据
			axios.get('/findpage?page='+page+"&rows="+rows)
				.then(function(res2){
					_this.list = res2.data.list;//当前页显示订单对象集合
					_this.total = res2.data.total;//订单总数
					//使用pagedivjs公共JS方法处理分页,此方法在base.js文件中
					//需要传入每次点击分页时调用的JS方法,本例中为dopageload,但需要传入其VUE对象限定app,
					//app是在153行定义的 var app = new Vue({
					_this.pagediv = pagedivjs('app.dopageload',_this.page,_this.rows,_this.total);//res2.data.pagediv;
			});
		},
		dosave:function(){//使用Ajax保持订单方法
			_this = this;
			axios.post('/saveorder',this.order)
				.then(function(res){
					if(res.data == true)
					{
						alert('保持成功');
						//保存成功后刷新订单列表
						_this.dopageload(_this.page,_this.rows);
						//关闭当前订单明细窗口
						doclose();
					}
					else
						alert('保存失败');
			});
		}
	}
});
	</script>
</body>
</html>

设计后台Controller

package com.test.ctrl;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONObject;
import com.test.model.AddressInfo;
import com.test.model.OrderInfo;
import com.test.model.OrderItemInfo;
import com.test.service.IService;
import com.test.util.PageUtil;

@Controller
public class OrderCtrl {
	@Reference(timeout=3000)
	private IService serv;
	
	/**
	 * 跳转页面
	 * @param req
	 * @param page
	 * @param rows
	 * @return
	 */
	@RequestMapping("/list")
	public String list(HttpServletRequest req,Integer page,Integer rows)
	{
		return "order";
	}
	
	/**
	 * Ajax异步加载分页数据
	 * @param page
	 * @param rows
	 * @return
	 */
	@RequestMapping("/findpage")
	@ResponseBody
	public Map findpage(Integer page,Integer rows)
	{
		System.out.println("page="+page+",rows="+rows);
		if(page == null)
			page = 1;
		if(rows == null)
			rows = 4;
		System.out.println("page="+page+",rows="+rows);
		Map map = serv.getOrder(page,rows);
		List<OrderInfo> orders = (List<OrderInfo>)map.get("orders");
		System.out.println("orders="+orders);
		Long total = (Long)map.get("total");
		Map m = new HashMap();
		m.put("total", total);
		m.put("list", orders);
		
		String url = "/list";
		PageUtil pu = new PageUtil(url,page,rows,total);
		String htmlPage = pu.toHtml();
		m.put("pagediv", htmlPage);
		
		return m;
	}
	
	@RequestMapping("/address")
	public String address(HttpServletRequest req)
	{
		return "address";
	}
	
	@RequestMapping("/saveorder")
	@ResponseBody
	public Boolean saveorder(HttpServletRequest req)
	{
		try
		{
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			FileUtil.copyStream(req.getInputStream(), baos);
			JSONObject jsonObj = JSONObject.parseObject(new String(baos.toByteArray()));
			OrderInfo oi = (OrderInfo)JSONObject.toJavaObject(jsonObj,OrderInfo.class);
			oi.setPayment_time(new Timestamp(System.currentTimeMillis()));
			oi.setCreate_time(new Timestamp(System.currentTimeMillis()));
			if(oi.getOrder_id() == null)
				serv.saveOrder(oi);
			else
				serv.updateOrder(oi);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return true;
	}
	
	@RequestMapping("/findorder")
	@ResponseBody
	public OrderInfo findorder(String id)
	{
		Integer id2 = null;
		try
		{
			id2 = Integer.parseInt(id);
		}
		catch(Exception e)
		{}
		OrderInfo oi = null;
		if(id2 != null)
			oi = serv.getOrderById(id2);
		List<AddressInfo> plist = this.findprovince();
		if(oi != null)
		{
			List<OrderItemInfo> items = serv.getItemByOrderId(id2);
			oi.setItems(items);
			oi.setProvinceList(plist);
			oi.setCityList(this.findcity(oi.getProvince()));
			oi.setCountyList(this.findcounty(oi.getCity()));
		}
		else
		{
			oi = new OrderInfo();
			oi.setProvince(plist.get(0).getCode());
			oi.setProvinceList(plist);
			List<AddressInfo> clist = this.findcity(oi.getProvince());
			oi.setCityList(clist);
			oi.setCity(clist.get(0).getCode());
			List<AddressInfo> ctlist = this.findcounty(oi.getCity());
			oi.setCountyList(ctlist);
			oi.setCounty(ctlist.get(0).getCode());
		}
		return oi;
	}
	
	@RequestMapping("/findprovince")
	@ResponseBody
	public List<AddressInfo> findprovince()
	{
		return serv.findProvince();
	}
	
	@RequestMapping("/findcity")
	@ResponseBody
	public List<AddressInfo> findcity(String code)
	{
		List<AddressInfo> lst = new ArrayList<AddressInfo>();
		List<AddressInfo> rtns = serv.findCityByPrvnc(code);
		for(AddressInfo ai:rtns)
		{
			if(!ai.getCode().equals(code))
				lst.add(ai);
		}
		return lst;
	}
	
	@RequestMapping("/findcounty")
	@ResponseBody
	public List<AddressInfo> findcounty(String code)
	{
		List<AddressInfo> lst = new ArrayList<AddressInfo>();
		List<AddressInfo> rtns = serv.findCountyByCity(code);
		for(AddressInfo ai:rtns)
		{
			if(!ai.getCode().equals(code))
				lst.add(ai);
		}
		return lst;
	}
}

工具JS前台分页方法


/**
 * 使用VUE前台分页公共方法
 * @param js 点击页面调用JS方法
 * @param page 查询页码
 * @param rows 每页显示记录数
 * @param total 总记录数
 * @returns {String}
 */
function pagedivjs(js,page,rows,total)
{
	var pages = 0;
	if(total%rows==0)
		pages = parseInt(total/rows);
	else
		pages = parseInt(total/rows) + 1;
	var pageDiv = "<div id='pagediv'>";
	page=1;
	pageDiv = pageDiv + "<a href='javascript:"+js+"("+page+","+rows+");'>首页</a>";
    page = (page==1)?1:(page-1);
    pageDiv = pageDiv + "<a href='javascript:"+js+"("+page+","+rows+");'>上一页</a>";
    for(var i=1;i<=pages;i++)
    {
        if(i == page)
        	pageDiv = pageDiv + "<a href='javascript:"+js+"("+i+","+rows+");'><b><font color='red'>"+i+"</font></b></a>&nbsp;";
        else
        	pageDiv = pageDiv + "<a href='javascript:"+js+"("+i+","+rows+");'>"+i+"</a>&nbsp;";
    }
    page = (page==pages)?pages:(page+1);
    pageDiv = pageDiv + "<a href='javascript:"+js+"("+page+","+rows+");'>下一页</a>";
    //定义尾页连接
    page = pages;
    pageDiv = pageDiv + "<a href='javascript:"+js+"("+page+","+rows+");'>尾页</a>";
    pageDiv = pageDiv + "&nbsp;&nbsp;&nbsp;&nbsp;第"+page+"/"+pages+"页";
    pageDiv = pageDiv + "&nbsp;&nbsp;&nbsp;&nbsp;共"+total+"条记录";
    pageDiv = pageDiv + "</div>";
    return pageDiv;
}

测试效果

在这里插入图片描述
在这里插入图片描述

源代码下载
https://pan.baidu.com/s/1Imf_-_5rgnL9LjSc3Ot6Ug

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值