当前位置: 首页 > article >正文

web课程设计--酷鲨商城-springboot和vue

文章目录

      • 页面截图
      • 技术分析
      • 数据库
      • 代码地址

页面截图

登陆页面:

分类列表

添加分类

轮播图列表

添加轮播图

商品列表

添加商品信息

技术分析

前端使用 html页面的 vue.js(vue2)和element-ui绘制前端界面

后台使用Springboot+mybatis来实现crud。还有一个文件上传功能,保存在本地文件夹上面

数据库

数据库比较简单,一共只有四张表
在这里插入图片描述
一张轮播图表、一个分类表、一个产品表、一张用户表

```plain
-- MySQL dump 10.13  Distrib 8.0.29, for Win64 (x86_64)
--
-- Host: 127.0.0.1    Database: cs
-- ------------------------------------------------------
-- Server version   8.0.29

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `banner`
--

DROP TABLE IF EXISTS `banner`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `banner` (
  `id` int NOT NULL AUTO_INCREMENT,
  `url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `banner`
--

LOCK TABLES `banner` WRITE;
/*!40000 ALTER TABLE `banner` DISABLE KEYS */;
INSERT INTO `banner` VALUES (1,'/imgs/b1.jpg'),(2,'/imgs/b2.jpg'),(3,'/imgs/b3.jpg'),(4,'/imgs/b4.jpg'),(5,'5b10df54-31f6-4931-b559-0dc69b819cb2.png');
/*!40000 ALTER TABLE `banner` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `category`
--

DROP TABLE IF EXISTS `category`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `category` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `category`
--

LOCK TABLES `category` WRITE;
/*!40000 ALTER TABLE `category` DISABLE KEYS */;
INSERT INTO `category` VALUES (1,'精彩活动'),(2,'当季女装'),(3,'品牌男装'),(4,'医药健康'),(5,'美妆彩妆'),(6,'儿童用品');
/*!40000 ALTER TABLE `category` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `product`
--

DROP TABLE IF EXISTS `product`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `product` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(100) DEFAULT NULL,
  `url` varchar(200) DEFAULT NULL,
  `price` double(10,2) DEFAULT NULL,
  `old_price` double(10,2) DEFAULT NULL,
  `sale_count` int DEFAULT NULL,
  `num` int DEFAULT NULL,
  `view_count` int DEFAULT NULL,
  `created` timestamp NULL DEFAULT NULL,
  `category_id` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `product`
--

LOCK TABLES `product` WRITE;
/*!40000 ALTER TABLE `product` DISABLE KEYS */;
INSERT INTO `product` VALUES (1,'苹果','c296223d-6904-4d47-9890-e7fe4f5a328b.png',12.00,12.00,12,12,1,'2024-12-26 13:59:21',1);
/*!40000 ALTER TABLE `product` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `user`
--

DROP TABLE IF EXISTS `user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `nick` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `user`
--

LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,'admin','123456','管理员');
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2024-12-26 22:45:20



<h3 id="c43eE">代码分析</h3>
登录页面代码,一个表单  输入用户名和密码。点击登录后向后端发送login请求,发送post请求携带表单参数。

```plain
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/index.css">
    <style>
        body {
            margin: 0;
            background-image: url("imgs/bg.jpg");
            background-size: cover;
            text-align: center;
        }
        h1 {
            font-size: 72px;
            color: rgb(0,150,220);
            margin-bottom: 0;
        }
        img { width: 100px; }
        h2 {
            font-size: 32px;
            color: rgb(0,150,220);
            margin: 0;
        }
    </style>
</head>
<body>
<div id="app">
    <h1>欢迎来到酷鲨商城</h1>
    <img src="imgs/shark.png" alt="">
    <h2>CoolSharkMall</h2>
    <el-card style="width: 600px;height: 300px;margin: 0 auto;background-color: rgba(255,255,255,0.3)">
        <el-form style="width: 400px;margin: 30px auto" label-width="60px">
            <el-form-item label="用户名">
                <el-input type="text" placeholder="请输入用户名" v-model="user.username"></el-input>
            </el-form-item>
            <el-form-item label="密码">
                <el-input type="password" placeholder="请输入密码" v-model="user.password"></el-input>
            </el-form-item>
            <el-form-item>
                <el-button style="position: relative;right: 30px" type="primary" @click="login()">登录</el-button>
            </el-form-item>
        </el-form>
    </el-card>
</div>

<!-- 引入 Vue -->
<script src="js/vue.min.js"></script>

<!-- 引入 Axios -->
<script src="js/axios.js"></script>

<!-- 引入 Element UI 样式和 JavaScript -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui@2.15.9/lib/theme-chalk/index.css">
<script src="https://cdn.jsdelivr.net/npm/element-ui@2.15.9/lib/index.js"></script>

<script>
    let v = new Vue({
        el: '#app',
        data: function() {
            return {
                user: {
                    username: "",
                    password: ""
                }
            }
        },
        methods: {
            login() {
                axios.post("/login", this.user).then((response) => {
                    if (response.data == 1) {
                        location.href = "/admin.html";
                    } else if (response.data == 2) {
                        this.$message.error("用户名不存在!");
                    } else {
                        this.$message.error("密码错误!");
                    }
                }).catch((error) => {
                    console.error("登录请求失败:", error);
                    this.$message.error("登录请求失败,请稍后再试。");
                });
            }
        }
    });
</script>

</body>
</html>

后端进行参数的接收

@RequestMapping("/login")
public int login(@RequestBody User user, HttpSession session) {
    User u = mapper.selectByUsername(user.getUsername());
    if (u != null) {
        if (user.getPassword().equals(u.getPassword())) {
            session.setAttribute("user", u);
            return 1;
        }
        return 3;
    }
    return 2;
}

管理台的页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <!-- import CSS -->
    <link rel="stylesheet" href="css/index.css">
</head>
<body>
<div id="app">
    <el-container>
        <el-header style="background-color: #0095d7">
            <h1 style="color: white;font-size: 22px">CoolShark商城后台管理系统
                <span style="float: right;font-size: 15px">欢迎{{user.nick}}回来!
                    <a href="javascript:void(0)" @click="logout()">退出登录</a>
                </span>
            </h1>
        </el-header>
        <el-container>
            <el-aside width="200px">
                <!--侧边栏开始-->
                <el-menu class="el-menu-vertical-demo"
                         @select="handleSelect">
                    <el-submenu index="1">
                        <template slot="title">
                            <i class="el-icon-s-flag">分类管理</i>
                        </template>
                        <el-menu-item index="1-1">分类列表</el-menu-item>
                        <el-menu-item index="1-2">添加分类</el-menu-item>
                    </el-submenu>
                    <el-submenu index="2">
                        <template slot="title">
                            <i class="el-icon-picture">轮播图管理</i>
                        </template>
                        <el-menu-item index="2-1">轮播图列表</el-menu-item>
                        <el-menu-item index="2-2">添加轮播图</el-menu-item>
                    </el-submenu>
                    <el-submenu index="3">
                        <template slot="title">
                            <i class="el-icon-shopping-cart-2">商品管理</i>
                        </template>
                        <el-menu-item index="3-1">商品列表</el-menu-item>
                        <el-menu-item index="3-2">添加商品</el-menu-item>
                    </el-submenu>
                </el-menu>
                <!--侧边栏结束-->
            </el-aside>
            <el-main>
                <!--分类表格开始-->
                <el-table v-if="selectedIndex=='1-1'" :data="categoryArr" style="width: 100%">
                    <!--type="index" 设置当前列展示编号信息-->
                    <el-table-column type="index" label="编号" width="180">
                    </el-table-column>
                    <el-table-column prop="name" label="分类名称" width="180">
                    </el-table-column>
                    <el-table-column label="操作">
                        <!--scope代表的是当前行所包含的数据,里面有当前行对应的位置和对象-->
                        <template slot-scope="scope">
                            <el-popconfirm title="你确定删除吗?"
                                           @confirm="categoryDelete(scope.$index, scope.row)">
                                <el-button slot="reference" size="mini" type="danger">删除</el-button>
                            </el-popconfirm>
                        </template>
                    </el-table-column>
                </el-table>
                <!--分类表格结束-->
                <!--轮播图表格开始-->
                <el-table v-if="selectedIndex=='2-1'" :data="bannerArr" style="width: 100%">
                    <!--type="index" 设置当前列展示编号信息-->
                    <el-table-column type="index" label="编号" width="180">
                    </el-table-column>
                    <el-table-column label="轮播图" width="180">
                        <template slot-scope="scope">
                            <img :src="scope.row.url" width="150" alt="">
                        </template>
                    </el-table-column>
                    <el-table-column label="操作">
                        <!--scope代表的是当前行所包含的数据,里面有当前行对应的位置和对象(scope.row)-->
                        <template slot-scope="scope">
                            <el-popconfirm title="你确定删除吗?"
                                           @confirm="bannerDelete(scope.$index, scope.row)">
                                <el-button slot="reference" size="mini" type="danger">删除</el-button>
                            </el-popconfirm>
                        </template>
                    </el-table-column>
                </el-table>

                <!--轮播图表格结束-->
                <!--商品表格开始-->
                <el-table v-if="selectedIndex=='3-1'" :data="productArr" style="width: 100%">
                    <!--type="index" 设置当前列展示编号信息-->
                    <el-table-column type="index" label="编号" width="180">
                    </el-table-column>
                    <el-table-column prop="title" label="商品标题" width="150"></el-table-column>
                    <el-table-column prop="price" label="价格" width="100"></el-table-column>
                    <el-table-column prop="saleCount" label="销量" width="100"></el-table-column>
                    <el-table-column label="商品图片" width="180">
                        <template slot-scope="scope">
                            <img :src="scope.row.url" width="150" alt="">
                        </template>
                    </el-table-column>
                    <el-table-column label="操作">
                        <!--scope代表的是当前行所包含的数据,里面有当前行对应的位置和对象(scope.row)-->
                        <template slot-scope="scope">
                            <el-popconfirm title="你确定删除吗?"
                                           @confirm="productDelete(scope.$index, scope.row)">
                                <el-button slot="reference" size="mini" type="danger">删除</el-button>
                            </el-popconfirm>
                        </template>
                    </el-table-column>
                </el-table>
                <!--商品表格结束-->

            </el-main>
        </el-container>
    </el-container>
</div>
</body>
<!-- import Vue before Element -->
<!--引入Vue框架-->
<script src="js/vue.min.js"></script>
<!-- import JavaScript -->
<script src="js/index.js"></script>
<script src="js/axios.js"></script>

<script>
    let v = new Vue({
        el: '#app',
        data: function () {
            return {
                selectedIndex: "1-1",
                categoryArr: [],
                bannerArr: [],
                productArr: [],
                user: {}
            }
        },
        methods: {
            logout() {
                axios.get("/logout").then(function () {
                    location.href = "/";
                })
            },
            handleSelect(index) {
                console.log(index);
                if (index == "1-2") {
                    console.log("添加分类");
                    v.$prompt('请输入分类名称', '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                    }).then(({value}) => {
                        console.log("分类名:" + value)
                        let name = value;
                        if (name == null) {
                            v.$message.error("分类名称不能为空!");
                            return;
                        }
                        //发请求添加分类
                        axios.get("/category/insert?name=" + name).then(function () {
                            location.reload();//刷新页面
                        })
                    }).catch(() => {

                    });

                } else if (index == "2-2") {
                    console.log("添加轮播图");
                    location.href = "/insertBanner.html"

                } else if (index == "3-2") {
                    console.log("添加商品");
                    location.href = "/insertProduct.html";
                } else {
                    v.selectedIndex = index;
                }
            },
            categoryDelete(index, category) {
                //发出删除分类的请求
                axios.get("/category/delete?id=" + category.id).then(function () {
                    //删除成功后 删除数据里面的对象 从而让页面跟着改变
                    //splice(a,b)数组的删除元素方法, a代表下标 b代表数量
                    v.categoryArr.splice(index, 1);
                })
            },
            productDelete(index, product) {
                //发出删除作品的请求
                axios.get("/product/delete?id=" + product.id).then(function () {
                    //删除成功后 删除数组中的内容让页面跟着改变
                    v.productArr.splice(index, 1);
                })
            },
            bannerDelete(index, banner) {
                //发出删除轮播图的请求
                axios.get("/banner/delete?id=" + banner.id).then(function () {
                    //删除成功后 删除数组中的内容让页面跟着改变
                    v.bannerArr.splice(index, 1);
                })
            }
        },
        created: function () {
            //发请求获取当前登录的用户信息
            axios.get("/currentUser").then(function (response) {
                v.user = response.data;
                if (response.data == "") {
                    //如果没有登录则显示登录页面
                    location.href = "/login.html";
                }
            })

            //发请求获取分类数据
            axios.get("/category/select").then(function (response) {
                v.categoryArr = response.data;
            })
            //发请求获取轮播图数据
            axios.get("/banner/select").then(function (response) {
                v.bannerArr = response.data;
            })
            //发请求获取商品数据
            axios.get("/product/select").then(function (response) {
                v.productArr = response.data;
            })
        }
    })
</script>
</html>

后端文件上传功能:

package org.wanho.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

@RestController
public class UploadController {
    //读取application.properties文件中的内容 并赋值给变量
    @Value("${dirPath}")
    private String dirPath;

    @RequestMapping("/upload")
    public String upload(MultipartFile picFile) throws IOException {
        System.out.println("picFile = " + picFile);
        //得到文件的原始文件名
        String fileName = picFile.getOriginalFilename();
        //得到文件名的后缀部分    abc.jpg     .jpg
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        //得到唯一的文件夹 UUID.randomUUID()得到唯一标识符 是一个字符串
        fileName = UUID.randomUUID()+suffix;
        System.out.println("新文件名="+fileName);
        //保存文件的文件夹
        File dirFile = new File(dirPath);
        //如果不存在则创建
        if (!dirFile.exists()){
            dirFile.mkdirs();
        }
        //得到文件的完整路径    F:/files/xxxxx.jpg
        String filePath = dirPath+"/"+fileName;
        //把文件保存到filePath这个路径   异常抛出
        picFile.transferTo(new File(filePath));
        //把新的文件名响应出去, 因为删除图片时需要用到
        return fileName;
    }

    @RequestMapping("/remove")
    public void remove(String fileName){
        System.out.println("删除的文件名 = " + fileName);
        String filePath = dirPath+"/"+fileName;
        //删除文件
        new File(filePath).delete();
        System.out.println(filePath);
    }

}

代码地址

https://gitee.com/z-zhou-xin/shark-mall.git


http://www.kler.cn/a/463891.html

相关文章:

  • 浅谈分布式共识算法
  • Git 树形图表不显示问题
  • 【paddle】初次尝试
  • Redis(二)value 的五种常见数据类型简述
  • 给vscode的新项目选择虚拟环境
  • UnityRenderStreaming使用记录(三)
  • Solon 加入 GitCode:助力国产 Java 应用开发新飞跃
  • OpenGL入门最后一章观察矩阵(照相机)
  • 【2024年-6月-14日-开源社区openEuler实践记录】探索 test - tools:高效测试的开源宝库
  • 电子电器架构 --- 自动驾驶技术中的LiDAR
  • windows编译llama.cpp GPU版本
  • Java Web开发基础——Java Web项目中的MVC设计模式
  • Leetcode打卡:二叉树中的链表
  • C++进阶重点知识(一)|智能指针|右值|lambda|STL|正则表达式
  • 《深入浅出HTTPS​​​​​​​​​​​​​​​​​》读书笔记(23):密钥协商算法(续)
  • ChatGLM2-6B模型推理流程和模型架构详解
  • SpringBoot_第二天
  • 机器学习中回归预测模型中常用四个评价指标MBE、MAE、RMSE、R2解释
  • 【从零开始入门unity游戏开发之——C#篇38】C#预处理器指令
  • locate() 在MySQL中的用法
  • 关于部署异常的处理问题
  • 网络渗透测试实验四:CTF实践
  • Spring Boot 嵌套事务详解及失效解决方案
  • leetcode hot 100 杨辉三角
  • python-leetcode-轮转数组
  • JVM实战—G1垃圾回收器的原理和调优