文章目录
登陆后用户对购物车的操作
1 获得登录用户购买商品数量,及将固定用户修改为当前用户
1.1 客户端
1.1.1 ui界面的改变
<el-badge :value="carCount" class="item">
<el-button type="success"
icon="el-icon-shopping-cart-full"
@click="$router.push('/showCar')">
购物车
</el-button>
</el-badge>
1.1.2 得到后端数据,并做出处理
data(){
return{
curUserInfo:null,//用户信息
carCount:0,//当前用户购物车中商品数量
}
},
methods: {
getCurUserInfo(){
this.curUserInfo= JSON.parse(window.sessionStorage.getItem("curUserInfo"));
if(this.curUserInfo!=null){
//获得当前用户商品数量
this.getCarCount();
}
},
getCarCount(){
this.$axios
.get("car/getCarCount")
.then(response=>{
this.carCount =response.data;
})
.catch(err=>{
console.log(err)
})
},
}
1.2 服务端
1.2.1 Controller添加获得商品数量方法
@GetMapping("/getCarCount")
public Integer getCarCount(HttpSession session){
CurUserInfo curUserInfo = (CurUserInfo) session.getAttribute("curUserInfo");
return carService.getCarCount(curUserInfo.getUser_id());
}
1.2.2 Service层进行对应修改
- CarService
Integer getCarCount(Integer user_id);
- CarServiceImpl
@Override
public Integer getCarCount(Integer user_id) {
//redis获取当前购物车
Map<Integer, Car> carMap = (Map<Integer, Car>) hashOperations.get("cars", "user:" + user_id);
return carMap.size();
}
1.2.3 将原本设置的固定用户修改为当前用户
- Controller层
@RestController
@RequestMapping("/car")
public class CarController {
@Resource
private CarService carService;
//注入session
@Resource
private HttpSession session;
@PostMapping("/addCar")
public Result addCar(@RequestBody Car car) {
try {
//session获得当前用户信息
CurUserInfo curUserInfo = (CurUserInfo) session.getAttribute("curUserInfo");
car.setUser_id(curUserInfo.getUser_id());
carService.addCar(car);
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.fail(500, "商品添加失败!!!");
}
}
@GetMapping("/queryCarInfo")
public List<Car> queryCarInfo() {
CurUserInfo curUserInfo = (CurUserInfo) session.getAttribute("curUserInfo");
return carService.queryCarInfo(curUserInfo.getUser_id());
}
@PutMapping("/updateCarCount")
public Result updateCarCount(@RequestBody Car car){
try {
CurUserInfo curUserInfo = (CurUserInfo) session.getAttribute("curUserInfo");
car.setUser_id(curUserInfo.getUser_id());
carService.updateCarCount(car);
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.fail(500, "数字不能为0");
}
}
@DeleteMapping("/delCarByBookId")
public Result delCarByBookId(Integer book_id){
try {
CurUserInfo curUserInfo = (CurUserInfo) session.getAttribute("curUserInfo");
carService.delCarByBookId(curUserInfo.getUser_id(),book_id);
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.fail(500, "删除失败!!");
}
}
@GetMapping("/getCarCount")
public Integer getCarCount(){
CurUserInfo curUserInfo = (CurUserInfo) session.getAttribute("curUserInfo");
return carService.getCarCount(curUserInfo.getUser_id());
}
}
2 购物车实现-计算要购买商品的总价格
2.1 客户端
2.1.1 购物车页面添加总价UI
<el-table
:data="carList"
border
style="width: 100%"
empty-text="暂无商品"
@selection-change="getSum"><!--添加获得总价事件-->
<div class="down">
<div class="carSum">
<label style="color: black">合计:</label>
<label style="color: red; margin-top: 20px; font-size: 10px ;">¥</label>
<label style="color: red;">0</label>
<el-button type="warning" size="small" round="true" style="margin-right: 80px; margin-left: 10px;font-size: 15px;" > 结算 </el-button>
</div>
</div>
<style scoped>
.down{
position:fixed;
bottom:0px;
width:100%;
height: 50px;
background-color:rgba(0, 0, 0, 0.3);
/* opacity: 0.3; */
text-align: right;
}
.carSum{
margin: 10px auto;
}
</style>
2.1.2 选择商品后得到所需商品总价处理
data(){
return{
sum:0,
}
}
getSum(selection){
this.sum=0;
//遍历选择的项并计算价格
for(let row of selection){
this.sum= this.sum+row.book_price*row.car_count;
}
}
2.1.3 修改购物车里更新数量
此时出现问题,当我们修改数量时,由于以前所做是修改数量,让数据重新查询,会页面刷新,导致本来选择的商品不选择,下面我们对以前功能做出修改
-
我们让改变事件的方法传递数据改为
row
<template slot-scope="scope"> <el-input-number size="small" v-model="scope.row.car_count" :min="1" @change="updateCarCount(scope.row)"></el-input-number> </template>
-
对应方法做出改变
updateCarCount(row){ this.$axios .put('car/updateCarCount', {"book_id":row.book_id, "car_count": row.car_count}) .then(response => { let result=response.data; if(result.success){ // this.queryCars(); row.total=row.book_price*row.car_count; }else{ this.$notify.error({ title: '错误', message: '请输入有效数字' }); } }) .catch(error => { console.log(error) }) }
此时问题,页面不刷新了,但是改变数量,下面总价不随之改变
- 设置一数组,存储选中商品
data(){
return{
sum:0,
salBooks:[],//要购买商品的数组
}
}
- 向选择的商品赋给数组
getSum(selection){
//将选择商品赋给数组
this.salBooks=selection;
this.sum=0;
//遍历选择的项并计算价格
for(let row of selection){
this.sum= this.sum+row.book_price*row.car_count;
}
}
- 点击修改数量,计算总价格
updateCarCount(row){
this.$axios
.put('car/updateCarCount',
{"book_id":row.book_id,
"car_count": row.car_count})
.then(response => {
let result=response.data;
if(result.success){
// this.queryCars();
row.total=row.book_price*row.car_count;
//清空原来总价
this.sum =0;
//改变总价格,如果修改数量商品时被修改的才修改总价格
for(let salBook of this.salBooks){
//改变价格
this.sum =this.sum +salBook.book_price*salBook.car_count;
}
}else{
this.$notify.error({
title: '错误',
message: '请输入有效数字'
});
}
})
.catch(error => {
console.log(error)
})
}
3 从购物车到购买确认购买页面的处理
3.1 客户端
3.1.1 点击进入确认购买页面
<el-button type="warning" size="small" round
style="margin-right: 80px; margin-left: 10px;font-size: 15px;"
:disabled="sum == 0 ? true : false"
s@click="$router.push({path:'/ConfirmSal',query:{'salBooks':salBooks}})">
结算
</el-button>
3.1.2 确认购买页面及配置路由
- ConfirmSal页面
<template>
<div class="showCar-Container">
<div class="car_list">
<el-table
:data="salBooks"
border
style="width: 100%"
empty-text="暂无商品"
@selection-change="getSum"><!--添加获得总价事件-->
<el-table-column
align="center"
type="selection">
</el-table-column>
<el-table-column
align="center"
type="index"
label="序号">
</el-table-column>
<el-table-column
align="center"
prop="book_name"
label="商品名称">
</el-table-column>
<el-table-column
align="center"
label="商品照片">
<template slot-scope="scope">
<img :src="require('@/assets/images/books/'+scope.row.book_image)" class="image">
</template>
</el-table-column>
<el-table-column
align="center"
prop="book_price"
label="单价">
</el-table-column>
<el-table-column
align="center"
prop="car_count"
label="购买数量">
</el-table-column>
<el-table-column
align="center"
label="总计">
<template slot-scope="scope">
{{ scope.row.car_count* scope.row.book_price }}
</template>
</el-table-column>
</el-table>
</div>
<div class="down">
<div class="carSum">
<label style="color: black">合计:</label>
<label style="color: red; margin-top: 20px; font-size: 10px ;">¥</label>
<label style="color: red;">{{ sum }}</label>
<el-button
type="warning"
size="small"
round
style="margin-right: 80px; margin-left: 10px;font-size: 15px;"
:disabled="sum == 0 ? true : false">
结算
</el-button>
<el-button
type="info"
size="small"
round
style="margin-right: 80px; margin-left: 10px;font-size: 15px;"
@click="$router.push('/showCar')">
返回购物车
</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.showCar-Container{
margin:0;padding:0;height:100%;width:100%;
}
.down{
position:fixed;
bottom:0px;
width:100%;
height: 50px;
background-color:rgba(0, 0, 0, 0.3);
/* opacity: 0.3; */
text-align: right;
}
.carSum{
margin: 10px auto;
}
.image{
width: 80px;
height: 80px;
}
</style>
- 配置路由
import ConfirmSal from "../views/ConfirmSal.vue"
const routes = [
{
path: "/confirmSal",
name: "confirmSal",
component: ConfirmSal,
},
];
3.1.3 处理购物车传来的数据
export default {
data(){
return{
sum:0,
salBooks:[],//要购买商品的数组
}
},methods:{
getSum(){
this.sum=0;
for(let salBook of this.salBooks){
this.sum=this.sum+salBook.book_price*salBook.car_count;
}
},
},created(){
this.salBooks=this.$route.query.salBooks;
this.getSum();
}
}
4 添加订单
4.1 客户端
4.1.1 点击结算进入添加订单UI
<el-button
type="warning"
size="small"
round
style=" margin-left: 10px;font-size: 15px;"
:disabled="sum == 0 ? true : false"
@click="drawer = true">
结算
</el-button>
<div>
<el-drawer
title="添加联系人信息"
:visible.sync="drawer"
:direction="direction">
<el-form ref="form" :model="order" label-width="120px">
<el-form-item label="收货人姓名">
<el-input v-model="order.order_to_name"></el-input>
</el-form-item>
<el-form-item label="收货人联系方式">
<el-input v-model="order.order_to_phone"></el-input>
</el-form-item>
<el-form-item label="收货人联系地址">
<el-input v-model="order.order_to_address"></el-input>
</el-form-item>
<el-button type="warning" style="width:100%" @click="sale">确认购买</el-button>
</el-form>
</el-drawer>
</div>
data(){
drawer: false,//是否显示抽屉
direction: 'rtl',//设置抽屉的方向
}
4.1.2 向服务端传递数据并做出成功处理
地址,联系方式,姓名,要购买的订单
data(){
return{
salBooks:[],//要购买商品的数组
order: {},//订单对象
}
}
/**
* 确认购买按钮
*/
sale(){
//要购买的商品编号
let book_ids=[];
for(let salBook of this.salBooks){
book_ids.push(salBook.book_id)
}
//订单参数
let orderParam={"order":this.order,"book_ids":book_ids}
this.$axios.post("/order/addOrder", orderParam)
.then(response=>{
let result=response.data;
if(result.success){
//弹出提示框
this.$swal.fire({
icon: 'success',
title: result.message,
showConfirmButton: false,
timer:1000,
didClose:()=>{
this.$router.push("/ShowCar")
}
});
}else{
this.$swal.fire({
icon: 'error',
title: result.message,
showConfirmButton: false,
timer: 1000,
});
}
})
.catch(error=>{
console.log(error)
})
},
4.2 服务端
4.2.1 创建公共类-OrderParam
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderParam implements Serializable {
private Integer[] book_ids;
private Orders order;//订单
}
4.2.2 创建model-Orders
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Orders implements Serializable {
private String order_id;
private Integer user_id;
private String order_to_name;
private String order_to_address;
private String order_to_phone;
private Date order_time;
private Integer order_status;
private Double order_total_price;
}
4.2.3 创建model-OrderDesc
@AllArgsConstructor
@NoArgsConstructor
@Data
public class OrderDesc implements Serializable {
private Integer desc_id;
private String order_id;
private Integer book_id;
private Integer count;
}
4.2.4 创建Controller-OrderController
@RestController
@RequestMapping("/order")
public class OrderController {
@Resource
private OrderService orderService;
@Resource
private HttpSession session;
@PostMapping("/addOrder")
public Result addOrder(@RequestBody OrderParam orderParam ){
try {
CurUserInfo curUserInfo = (CurUserInfo) session.getAttribute("curUserInfo");
Orders order=orderParam.getOrder();
//设置订单用户id
order.setUser_id(curUserInfo.getUser_id());
List<OrderDesc> orderDescList =new ArrayList<>();
//将book_id封装到订单明细集合中
for (int book_id :orderParam.getBook_ids()){
OrderDesc orderDesc =new OrderDesc();
orderDesc.setBook_id(book_id);
orderDescList.add(orderDesc);
}
orderService.addOrder(order,orderDescList);
return Result.success("订单添加成功");
} catch (Exception e) {
e.printStackTrace();
return Result.fail(500,"订单添加失败");
}
}
}
4.2.3 创建Service层
- OrderService
public interface OrderService {
void addOrder(Orders orders, List<OrderDesc> orderDescList) throws Exception;
}
4.2.4 OrderServiceImpl实现具体功能
具体思路:
- 1.补全订单及其相关属性
- 2.向数据库添加订单和订单明细
- 3.从redis中删除已购买商品
4.2.4.1 添加生成订单编号工具类
设置订单编号
/**
* 生成订单编号工具类
*/
public class GenerateOrderId {
private static int num=0;
private static final int MIN_NUM=0;
private static final int MAX_NUM=10000000;
public static synchronized String getOrderId(){
String timeStr =new SimpleDateFormat("yyyyMMddHHmmssSS").format(new Date());
if (num>=MAX_NUM){
num=MIN_NUM;
}
String orderId =timeStr+num;
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
}
num++;
return orderId;
}
}
4.2.4.2 在carServcie添加根据用户id和图书id查询购物车信息
设置订单数量,需要从redis中读取(需要购买商品id)的信息里面有订单数量
- carServcie
Car getCarInfoById(int user_id,int book_id);
- carServiceImpl
@Override
public Car getCarInfoById(int user_id, int book_id) {
//得到对应用户的购物车
Map<Integer, Car> carMap = (Map<Integer, Car>) hashOperations.get("cars", "user:" + user_id);
return carMap.get(book_id);
}
4.2.4.3 向数据库添加订单和订单明细
- OrderMapper
@Repository
public interface OrderMapper {
//添加订单
@Insert("insert into myshopping.tbl_order values (#{order_id},#{user_id},#{order_to_name},#{order_to_address},#{order_to_phone},now(),default,#{order_total_price})")
void addOrder(Orders orders);
}
- OrderDescMapper
@Repository
public interface OrderDescMapper {
public void addOrderDesc(List<OrderDesc> descList);
}
- OrderDescMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.shopping.mapper.OrderDescMapper">
<insert id="addOrderDesc">
INSERT INTO myshopping.tbl_order_desc values
<foreach collection="descList" item="desc" separator=",">
(default,#{desc.order_id},#{desc.book_id},#{desc.count})
</foreach>
</insert>
</mapper>
4.2.4.4 OrderServiceImpl实现具体功能
此处会出现当订单添加成功或者但是订单信息没添加成功,不具有原子性
因此此处使用事务,使添加订单和添加订单信息,要么都添加成功,要么都添加失败
@Service
@Transactional //声明式事务,使用该注解,当前类中所有方法,都属于一个独立的事务
public class OrderServiceImpl implements OrderService {
@Resource
private CarService carService;
@Resource
private OrderDescMapper orderDescMapper;
@Resource
private OrderMapper orderMapper;
/**
* 添加订单
* 1.补全订单及其相关属性
* 2.向数据库添加订单和订单明细
* 3.从redis中删除已购买商品
* @param orders
* @param orderDescList
* @throws Exception
*/
@Override
public void addOrder(Orders orders, List<OrderDesc> orderDescList) throws Exception {
orders.setOrder_id(GenerateOrderId.getOrderId());//订单编号
double total = 0;
//遍历orderDescList并添加订单明细相关属性数据
for (OrderDesc orderDesc:orderDescList){
//设置订单编号
orderDesc.setOrder_id(orders.getOrder_id());
//从redis中读取购物车数据
Car car = carService.getCarInfoById(orders.getUser_id(), orderDesc.getBook_id());
//设置购买数量
orderDesc.setCount(car.getCar_count());
total=total+car.getCar_count()*car.getBook_price();
}
//设置订单总价格
orders.setOrder_total_price(total);
//向数据库添加数据
orderMapper.addOrder(orders);
orderDescMapper.addOrderDesc(orderDescList);
//从redis中删除购买商品
for (OrderDesc orderDesc:orderDescList){
carService.delCarByBookId(orders.getUser_id(),orderDesc.getBook_id());
}
}
}