Java大联盟
致力于最高效的Java学习
关注
B 站搜索:楠哥教你学Java
获取更多优质视频教程
前言
最近有不少小伙伴留言希望楠哥出一套 Spring Boot + Vue 项目实战教程,大家有需求,楠哥就会尽量满足大家,所以专程为大家做了一个教程,非常适合希望快速上手 Spring Boot + Vue 项目实战的同学。话不多说,直接来看项目。
项目名称:基于移动端的手机商城 PhoneStore
前端技术:Vue + Vant UI + less + axios
后端技术:Spring Boot + Spring Data JPA + MySQL
项目截图:
接下来楠哥就带领大家来完成代码的开发。
创建 Vue 工程
1、创建 Vue 工程,安装 Vant UI 和 less,命令如下。
安装 Vant UI
npm i vant -S
安装 less
cnpm install less less-loader --save
2、创建首页 Home.vue。
这里我们使用 Vant UI 提供的组件来完成,主要包括两个组件:Card 商品卡片和 Sku 商品规格,大家可以参考 Vant UI 官方文档:https://youzan.github.io/vant/#/zh-CN
我们这里简单说一下这两个组件的使用,Card 代码如下所示。
{{tag.name}}
购买
phones: [
{
id: 1,
title: "Honor 8A",
price: "2800.00",
desc: "魅焰红",
tag: [
{
name: "720P珍珠屏"
},
{
name: "Micro USB接口"
}
],
thumb: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg"
},
{
id: 5,
title: "HUAWEI nova 5 Pro",
price: "5450.00",
desc: "魅焰红",
tag: [
{
name: "内存3GB"
},
{
name: "Micro USB接口"
}
],
thumb: "../static/8a0f5be0-3c78-4f23-b58b-dc2a92f1f95a.jpg"
},
{
id: 9,
title: "SAMSUNG G S10",
price: "7254.00",
desc: "魅焰红",
tag: [
{
name: "720P珍珠屏"
},
{
name: "存储32GB"
}
],
thumb: "../static/a4f0cef8-59da-4f7c-abfa-d373f6648035.jpg"
},
{
id: 13,
title: "VIVO X27",
price: "2888.00",
desc: "魅焰红",
tag: [
{
name: "F/1.8光圈"
},
{
name: "Micro USB接口"
}
],
thumb: "../static/cdf065ec-e409-4204-93e6-600e172e461a.jpg"
},
{
id: 17,
title: "Meizu 16s",
price: "1220.00",
desc: "魅焰红",
tag: [
{
name: "720P珍珠屏"
},
{
name: "Micro USB接口"
}
],
thumb: "../static/1a2b8e30-6e98-405f-9a18-9cd31ff96c35.jpg"
}
]
num 表示商品数量,price 表示商品价格,desc 表示商品的描述信息,title 表示商品标题,thumb 是商品图片的链接,运行结果如下图所示。
Card 组件的使用较为简单,Sku 组件的使用会稍微复杂一些,具体代码如下所示。
买买买
sku = {
tree: [
{
k: "规格",
v: [
{
id: 1,
name: "32GB",
imgUrl: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg",
previewImgUrl: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg"
},
{
id: 2,
name: "64GB",
imgUrl: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg",
previewImgUrl: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg"
}
],
k_s: "s1"
}
],
list: [
{
s1: 1,
price: 280000,
stock_num: 5
},
{
s1: 2,
price: 320000,
stock_num: 5
}
],
price: "2800.00",
stock_num: 10,
none_sku: false,
hide_stock: false
}
v-model 表示是否显示 Sku 组件,sku 表示绑定的规格对象,goods 表示绑定的商品对象,hide-stock 表示是否隐藏库存。使用 Sku 组件的关键在于搞清楚 sku 和 goods 的对象结构。
其中 tree 表示具体规格数据,k 为规格名称,v 为规格选项,如下所示。
{
k: "规格",
v: [
{
id: 1,
name: "32GB",
imgUrl: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg",
previewImgUrl: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg"
},
{
id: 2,
name: "64GB",
imgUrl: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg",
previewImgUrl: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg"
}
],
k_s: "s1"
}
我们可以看到 v 对象中的属性,id 为规格编号,name 为规格名称,imgUrl 为规格图片,previewImgUrl 为规格预览图片。
需要注意的是,v 中的规格参数只是一部分,像规格价格,规格库存等信息没有体现,那么这部分数据在哪里呢?它们存放在另一个对象 list 中,如下所示。
list: [
{
s1: 1,
price: 280000,
stock_num: 5
},
{
s1: 2,
price: 320000,
stock_num: 5
}
]
那么问题来了,list 中的对象如何跟 v 中的对象进行关联呢?这就需要用到 k_s,它的作用就是映射 list 和 v 的,我们可以看到 k_s 的值为 s1,那么映射关系就是 v 中的 id 与 list 中的 s1 进行关联,相等则认为是同一组数据,搞清楚这个关系之后,再使用 Sku 组件就得心应手了,这里需要注意的是 list 中 price 属性的单位为分,我们在使用时需要注意单位转换,把分转换成元,具体结果如下图所示。
3、创建地址列表 AddressList.vue
这里我们使用 AddressList 组件来完成,代码如下所示。
list: [
{
areaCode: "440303",
id: 21,
name: "张三",
tel: "13678787878",
address: "广东省深圳市罗湖区科技路123号456室"
},
{
areaCode: "330104",
id: 22,
name: "小明",
tel: "13636363636",
address: "浙江省杭州市江干区789号"
}
]
v-model 表示选中的地址编号,list 表示要遍历的数据集合,default-tag-text 表示默认地址标签文字,@add 表示添加按钮绑定的方法,@edit 表示编辑按钮绑定的方法,@select 表示选中按钮绑定的方法,结果如下图所示。
4、创建新增地址 AddressNew.vue
这里我们使用 AddressEdit 组件,代码如下所示。
show-delete 表示是否添加删除按钮,ture 表示添加,false 表示不添加,默认值为 true。@save 和 @delete 分别为保存按钮和删除按钮所绑定的函数。
area-list 为绑定的省市区数据集合,官网提供了完整的数据,直接使用即可,网址:https://github.com/youzan/vant/blob/dev/src/area/demo/area.js,具体结果如下图所示。
5、创建修改地址 AddressEdit.vue
修改地址和新增地址使用同一个组件,唯一区别在于修改地址需要有默认数据,代码如下所示。
addressInfo: {
name: '张三',
tel: '13333333333',
areaCode: '130105',
addressDetail: '浙江省杭州市西湖区文三路 138 号东方通信大厦 7 楼 501 室'
}
address-info 为默认回填的数据,save-button-text 表示保存按钮所显示的文本,这里我们设置为“修改”即可。
6、创建订单详情 Detail.vue
这里需要结合 van-cell、van-card、van-submit-bar 等多个组件来完成,具体代码如下所示。
收货人:{{data.buyerName}}
{{data.tel}}
收货地址:{{data.address}}
配送方式
快递
商品金额
¥{{data.amount}}
运费
¥{{data.freight}}
data:{
orderId: "1586242977480760998",
buyerName: "小明",
phoneName: "Honor 8A",
payStatus: 0,
freight: 10,
tel: "13636363636",
address: "浙江省杭州市江干区789号",
num: 1,
specs: "32GB",
price: "2800.00",
icon: "../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg",
amount: 2800
}
这里需要说明的是 van-submit-bar 组件 price 属性的单位为分,所以我们在使用时需要注意单位的换算(分换算成元),否则会出现价格错误的问题,结果如下所示。
以上就是 Vue 工程中几个核心页面的搭建方式,其他页面搭建方式与之类似,这里我们就不再赘述,搞定了 Vue 工程,接下来咱们学习 Spring Boot 工程的搭建。
创建 Spring Boot 工程
1、我们是基于最新版 Spring Boot 2.2.6,在 IDEA 中使用 Spring Initializr 组件来创建工程,分别选择自动导入 Lombok、Spring Web、Spring Data JPA、MySQL Driver 依赖,如下图所示。
2、创建数据表,SQL 如下所示。
DROP TABLE IF EXISTS `buyer_address`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
SET character_set_client = utf8mb4 ;
CREATE TABLE `buyer_address` (
`address_id` int(11) NOT NULL AUTO_INCREMENT,
`buyer_name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT '买家名字',
`buyer_phone` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT '买家电话',
`buyer_address` varchar(128) COLLATE utf8mb4_general_ci NOT NULL COMMENT '买家地址',
`area_code` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '地址编码',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`address_id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='收货地址表';
DROP TABLE IF EXISTS `order_master`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
SET character_set_client = utf8mb4 ;
CREATE TABLE `order_master` (
`order_id` varchar(32) COLLATE utf8mb4_general_ci NOT NULL,
`buyer_name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT '买家名字',
`buyer_phone` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT '买家电话',
`buyer_address` varchar(128) COLLATE utf8mb4_general_ci NOT NULL COMMENT '买家地址',
`phone_id` int(11) DEFAULT NULL COMMENT '商品编号',
`phone_name` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '商品名称',
`phone_quantity` int(11) DEFAULT NULL COMMENT '商品数量',
`phone_icon` varchar(512) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '商品小图',
`specs_id` int(11) DEFAULT NULL COMMENT '规格编号',
`specs_name` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规格名称',
`specs_price` decimal(8,2) DEFAULT NULL COMMENT '规格单价',
`order_amount` decimal(8,2) NOT NULL COMMENT '订单总金额',
`pay_status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '支付状态,默认0未支付',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='订单表';
DROP TABLE IF EXISTS `phone_category`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
SET character_set_client = utf8mb4 ;
CREATE TABLE `phone_category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`category_name` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '类目名称',
`category_type` int(11) NOT NULL COMMENT '类目编号',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`category_id`),
UNIQUE KEY `uqe_category_type` (`category_type`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='类目表';
LOCK TABLES `phone_category` WRITE;
/*!40000 ALTER TABLE `phone_category` DISABLE KEYS */;
INSERT INTO `phone_category` VALUES (1,'魅焰红',1,'2020-04-01 10:39:43','2020-04-01 12:35:54'),(2,'极光蓝',2,'2020-04-01 10:39:43','2020-04-01 12:35:54'),(3,'铂光金',3,'2020-04-01 10:39:43','2020-04-01 12:35:54'),(4,'幻夜黑',4,'2020-04-01 10:39:43','2020-04-01 12:35:54');
/*!40000 ALTER TABLE `phone_category` ENABLE KEYS */;
UNLOCK TABLES;
DROP TABLE IF EXISTS `phone_info`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
SET character_set_client = utf8mb4 ;
CREATE TABLE `phone_info` (
`phone_id` int(11) NOT NULL AUTO_INCREMENT,
`phone_name` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '商品名称',
`phone_price` decimal(8,2) NOT NULL COMMENT '商品单价',
`phone_description` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '描述',
`phone_stock` int(11) NOT NULL COMMENT '库存',
`phone_icon` varchar(512) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '小图',
`category_type` int(11) NOT NULL COMMENT '类目编号',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`phone_tag` varchar(512) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签',
PRIMARY KEY (`phone_id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='商品表';
/*!40101 SET character_set_client = @saved_cs_client */;
LOCK TABLES `phone_info` WRITE;
/*!40000 ALTER TABLE `phone_info` DISABLE KEYS */;
INSERT INTO `phone_info` VALUES (1,'Honor 8A',2800.00,'魅焰红',2,'../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg',1,'2020-04-01 10:03:08','2020-04-10 09:20:41','720P珍珠屏&Micro USB接口'),(2,'Honor 10 青春版',2800.00,'极光蓝',100,'../static/8f0bd0d0-a11e-4185-927e-04b54ff4a1bd.jpg',2,'2020-04-01 10:03:08','2020-04-01 14:30:42','720P珍珠屏&EMUI9 Lite'),(3,'Honor V20',3450.00,'铂光金',100,'../static/fd7fee3c-a35c-477b-b007-9fda6e9c589a.jpg',3,'2020-04-01 10:14:54','2020-04-01 14:30:42','2+1独立三卡槽'),(4,'HUAWEI Mate 20 Pro',4550.00,'幻夜黑',100,'../static/cb819ad9-ec6f-4123-a4e9-aa629e2f8224.jpg',4,'2020-04-01 10:14:54','2020-04-01 14:30:42','内存3GB&EMUI9 Lite'),(5,'HUAWEI nova 5 Pro',5450.00,'魅焰红',100,'../static/8a0f5be0-3c78-4f23-b58b-dc2a92f1f95a.jpg',1,'2020-04-01 10:14:54','2020-04-01 14:30:42','内存3GB&Micro USB接口'),(6,'HUAWEI P30',8700.00,'极光蓝',100,'../static/6dcad185-315f-40f0-87f2-52910f49c8b7.jpg',2,'2020-04-01 10:14:54','2020-04-01 14:30:42','720P珍珠屏&内存3GB'),(7,'HUAWEI P30 Pro',8988.00,'铂光金',100,'../static/b12a46a9-3738-49ab-ab3a-6878539bd76b.jpg',3,'2020-04-01 10:14:54','2020-04-01 14:30:42','720P珍珠屏&Micro USB接口'),(8,'HUAWEI 畅想9 Plus',2760.00,'幻夜黑',100,'../static/15a5dcf2-4b50-41a0-93e8-08df97c21341.jpg',4,'2020-04-01 10:14:54','2020-04-01 14:30:42','内存3GB&存储32GB'),(9,'SAMSUNG G S10',7254.00,'魅焰红',100,'../static/a4f0cef8-59da-4f7c-abfa-d373f6648035.jpg',1,'2020-04-01 10:14:54','2020-04-01 14:30:42','720P珍珠屏&存储32GB'),(10,'OPPO K3',2889.00,'极光蓝',100,'../static/efc31538-a1f0-4dba-a673-4369f17e5708.jpg',2,'2020-04-01 10:14:54','2020-04-01 14:30:42','存储32GB&Micro USB接口'),(11,'Iphone XR',9888.00,'铂光金',100,'../static/4ef5a3c0-ad88-495f-a6bc-a31c1dde667b.jpg',3,'2020-04-01 10:14:54','2020-04-01 14:30:42','1300万像素&Micro USB接口'),(12,'MI 8',5888.00,'幻夜黑',100,'../static/aff8224c-3196-42a9-ae9e-4f06e20555c4.jpg',4,'2020-04-01 10:14:54','2020-04-01 14:30:42','内存3GB&存储32GB'),(13,'VIVO X27',2888.00,'魅焰红',100,'../static/cdf065ec-e409-4204-93e6-600e172e461a.jpg',1,'2020-04-01 10:14:54','2020-04-01 14:30:42','F/1.8光圈&Micro USB接口'),(14,'Iphone 6',5678.00,'极光蓝',100,'../static/899a9c64-62d0-416d-b320-e730b4585cb0.jpg',2,'2020-04-01 10:14:54','2020-04-01 14:30:42','720P珍珠屏&F/1.8光圈'),(15,'Iphone 7',5576.00,'铂光金',100,'../static/67aa6e9b-681f-4a6f-aae4-97eb3ec51b08.jpg',3,'2020-04-01 10:14:54','2020-04-01 14:30:42','720P珍珠屏&1300万像素'),(16,'Iphone 8',6212.00,'幻夜黑',100,'../static/a8b5b846-7fbb-4e7b-abcf-01ae73979000.jpg',4,'2020-04-01 10:14:54','2020-04-01 14:30:42','内存3GB&F/1.8光圈'),(17,'Meizu 16s',1220.00,'魅焰红',100,'../static/1a2b8e30-6e98-405f-9a18-9cd31ff96c35.jpg',1,'2020-04-01 10:14:54','2020-04-01 14:30:42','720P珍珠屏&Micro USB接口'),(18,'Iphone X',6770.00,'极光蓝',100,'../static/39197368-aeaf-48ea-b399-5ad65f7b6c47.jpg',2,'2020-04-01 10:14:54','2020-04-01 14:30:42','F/1.8光圈&Micro USB接口'),(19,'HUAWEI P20',5580.00,'铂光金',100,'../static/f382351b-7fc8-4b34-bcce-162085e75191.jpg',3,'2020-04-01 10:14:54','2020-04-01 14:30:42','1300万像素&Micro USB接口');
/*!40000 ALTER TABLE `phone_info` ENABLE KEYS */;
UNLOCK TABLES;
DROP TABLE IF EXISTS `phone_specs`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
SET character_set_client = utf8mb4 ;
CREATE TABLE `phone_specs` (
`specs_id` int(11) NOT NULL AUTO_INCREMENT,
`phone_id` varchar(32) COLLATE utf8mb4_general_ci NOT NULL,
`specs_name` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '规格名称',
`specs_stock` int(11) NOT NULL COMMENT '库存',
`specs_price` decimal(8,2) NOT NULL COMMENT '单价',
`specs_icon` varchar(512) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '小图',
`specs_preview` varchar(512) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '预览图',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`specs_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='商品规格表';
/*!40101 SET character_set_client = @saved_cs_client */;
LOCK TABLES `phone_specs` WRITE;
/*!40000 ALTER TABLE `phone_specs` DISABLE KEYS */;
INSERT INTO `phone_specs` VALUES (1,'1','32GB',0,280000.00,'../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg','../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg','2020-04-10 09:20:36','2020-04-01 14:16:36'),(2,'1','64GB',2,320000.00,'../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg','../static/e84a2e03-7f19-41d2-98a5-a5c16b7e252d.jpg','2020-04-07 10:06:22','2020-04-01 14:16:36');
/*!40000 ALTER TABLE `phone_specs` ENABLE KEYS */;
UNLOCK TABLES;
3、配置文件 application.yml 如下所示。
server:
port: 8181
spring:
datasource:
url: jdbc:mysql://localhost:3306/phone_store_demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
4、根据接口文档编写业务代码,文档如下所示。
5、Vue 直接调用 Spring Boot 的业务接口会存在跨越问题,我们可以在 Spring Boot 中添加配置类来解决,代码如下所示。
package com.southwind.phone_store_demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
6、源码链接
Vue
https://github.com/southwind9801/phone_store_demo_vue.git
Spring Boot
https://github.com/southwind9801/phone_store_demo_springboot.git
这样我们就完成了 Spring Boot + Vue 移动端商城的开发,配套视频教程已上传至 B 站,扫描下方二维码直接观看。
原创不易,如果楠哥的教程对你有所帮助,在看,转发来一波。
推荐阅读
1、B站原创,2020版前后端分离视频教程
2、Spring Boot源码解析
3、一文搞懂前后端分离
4、快速上手Spring Boot+Vue前后端分离
楠哥简介
资深 Java 工程师,微信号 nnsouthwind
《Java零基础实战》一书作者,今日头条认证大V
GitChat认证作者,B站认证UP主(楠哥教你学Java)
致力于帮助万千 Java 学习者持续成长。
有收获,就点个在看