SpringBoot+Vue implements online mall system

At the beginning of the project, we were required to use JavaWeb (java+jsp+servlet+MySQL+jdbc+css+js+jQuery) to implement, but after I learned a little bit of the framework, I switched to SpringBoot+Vue.

Notice! ! ! ! ! The serverIp in the code is the IP of my server , so it should be localhost if it is not on the server ! ! ! ! ! ! ! !

Online store project demonstration video: https://www.bilibili.com/video/BV1kY41117DH/

Table of contents

1. Product introduction

2. Product-oriented user groups

3. Range of products

4. Roles in the product

5. Functional requirements of the product

5.1 Classification of functional requirements

5.2 Functional Hierarchy Diagram

6. Non-functional requirements of the product

6.1 User Interface Requirements

6.2 Software and hardware environment requirements

6.3 Product Quality Requirements

Database Design:

Front page:

Online mall homepage:

​edit

Home page Home.vue source code:

 Product details page:

​Edit source code Detail.Vue

my shopping cart: 

My Order:

return data:

personal information:

 Source codePerson.vue

Contact the merchant:

 Background page:

Core code: 

1.UserController

2.TokenUtils 

3.CartController

4.EchartsController

5.FileController

6.MybatisPlusConfig

7.Constants

1. Product introduction

For the online shopping mall, its biggest advantage is to bring the greatest convenience to users. This convenience is not only reflected in the logistics outside the network, product discounts, etc., but also in the ease of use when operating the network, which can simulate The user's shopping behavior, creating a user shopping process that is as real and appropriate as possible. Therefore, when designing an online shopping mall, the most important thing is to complete the "user function". Secondly, the network management of numerous commodities, orders, and user information is self-evident for the operation efficiency of website operators, and these can be called "management functions".

2. Product-oriented user groups

This system is mainly for system administrators and ordinary users.

(1) System administrator: order management, user management, commodity management, etc.

(2) Ordinary users: The main business modules used include system login, registration, purchase of goods, and order query.

3. Range of products

This project is mainly divided into system setting module, user management module, product management module, purchased product management module, and order management module.

4. Roles in the product

Role Name

Responsibilities

general user

Register, log in, add shopping cart, product payment

administrator

Login, registration, commodity information management, user information management

5. Functional requirements of the product

5.1 Classification of functional requirements

Functional category

function name

describe

User Management

Personal Information Management

Manage users' personal information

User Management

Manage existing users

commodity management

Add products

Add items to the mall

delete item

Delete the products on the shelf in the mall

order management

Order Details Management

Process the order, ship the paid order, and receive the shipped goods

s

Pay for current outstanding orders

view product

View the product information of this order

shopping cart management

add to cart

Add item to cart

delete cart

Delete items in the current shopping cart

Merchandise settlement

Check out the items in the shopping cart

5.2 Functional Hierarchy Diagram

6. Non-functional requirements of the product

6.1 User Interface Requirements

Requirement name

Detailed requirements

Overall style

Mainly blue

compatibility

Can run on mainstream browsers (Firefox, Google, IE8+, 360 browsers)

6.2 Software and hardware environment requirements

Requirement name

Detailed requirements

Development language

Java or .NET

operating environment

Jdk1.6+ or .NET Framework 3.5 or above

database

Mysql5.0 or SqlServer 2005 or above

operating system

Windows Server2008

6.3 Product Quality Requirements

main quality attribute

Detailed requirements

correctness

No data calculation errors, no process errors

robustness

After the program makes an error, the system can catch the exception normally and will not cause the program to terminate

reliability

The system supports 7*24 uninterrupted operation, and the system will not crash due to complex calculations of system functions

performance, efficiency

The data request returns within 0.2S

ease of use

Functional use, simple operation, avoid tedious logic setting

clarity

Function results and names are clear to avoid user misunderstanding

safety

Users must log in successfully to use the corresponding functions according to their permissions

scalability

Provide a good system interface and support the development and expansion of subsequent functions

compatibility

Compatible with mainstream browsers (Firefox, Google, IE8+, 360 browsers)

portability

Can be better deployed to other versions of the Windows operating system

Database Design:

1.1 Database system:

SQL Server 2008 / My SQL, the server is MySQL8.0 version

1.2 Design tools:

Enterprise Architect

1.3 Connection tools:

Navicat, server is 1 core (vCPU) 2 GiB

Front page:

Online mall homepage:

 

Home page Home.vue source code:

<template>
  <div class="base">
    <div style="background-color: #545c64; width: 1510px">
      <el-menu background-color="#545c64" text-color="#fff" active-text-color="#ffd04b"
               class="el-menu-demo"
               mode="horizontal">
        <el-menu-item index="/home" @click="$router.push('/home')">在线商城首页</el-menu-item>
        <el-menu-item index="1" >
          <a href="https://www.jd.com" target="_blank" style="text-decoration: none">商城官网</a></el-menu-item>
        <el-menu-item index="/front/cart" @click="$router.push('/front/cart')">我的购物车<i class="el-icon-shopping-cart-1"/></el-menu-item>
        <el-menu-item index="/front/orders" @click="$router.push('/front/orders')">我的订单<i class="el-icon-truck"/></el-menu-item>
<!--        <el-menu-item index="/user" @click="$router.push('/user')" v-if="user.role == 1">后台管理</el-menu-item>-->
        <!--        <el-submenu index="7" v-if="user.role == 1">-->
        <!--          <template slot="title">后台管理</template>-->
        <!--          <el-menu-item index="/user" @click="$router.push('/user')">用户管理</el-menu-item>-->
        <!--          <el-menu-item index="/goods" @click="$router.push('/goods')">商品管理</el-menu-item>-->
        <!--          <el-menu-item index="/cart" @click="$router.push('/cart')">购物车管理</el-menu-item>-->
        <!--          <el-menu-item index="/orders" @click="$router.push('/orders')">订单管理</el-menu-item>-->
        <!--        </el-submenu>-->
        <div style="float: right; display: flex">
          <el-menu-item index="/login" @click="$router.push('/login')">登录/注册</el-menu-item>
<!--          <el-menu-item index="/register" @click="$router.push('/login')">退出商城</el-menu-item>-->
<!--          <el-menu-item index="/front/person" @click="$router.push('/front/person')">{
   
   { user.nickname }}</el-menu-item>-->
          <el-submenu index="7">
            <template slot="title">{
   
   { user.nickname }}</template>
            <el-menu-item index="/front/person" @click="$router.push('/front/person')">个人信息</el-menu-item>
            <el-menu-item index="/login" @click="$router.push('/login')">退出</el-menu-item>
          </el-submenu>
        </div>
      </el-menu>
    </div>
    <el-card style="height: 80px; background-color: white">
      <el-input style="width: 600px; margin-left: 400px" placeholder="请输入你要查询的商品" clearable v-model="name" size="big"></el-input>
<!--      <el-input style="width: 200px; margin-left: 10px" placeholder="请输入用户名" clearable suffix-icon="el-icon-user" v-model="username" ></el-input>-->
      <el-button type="primary" style="margin-left: 5px" @click="load" size="big"><i class="el-icon-search" />搜索</el-button>
    </el-card>

    <div style="width: 1500px; height: 410px; display: flex">
      <div style="width: 300px; text-align: right; padding-right: 10px; background-color: whitesmoke; margin: 10px 0 0">
        <ul style="margin: 10px 0; font-weight: inherit; font-size: 18px; color: #545c64">
          <li style="margin-top: 10px; cursor: pointer">手机</li>
          <li style="margin-top: 20px; cursor: pointer">电脑</li>
          <li style="margin-top: 20px; cursor: pointer">家装</li>
          <li style="margin-top: 20px; cursor: pointer">医药</li>
          <li style="margin-top: 20px; cursor: pointer">女装</li>
          <li style="margin-top: 20px; cursor: pointer">男装</li>
          <li style="margin-top: 20px; cursor: pointer">美妆</li>
          <li style="margin-top: 20px; cursor: pointer">食品</li>
        </ul>
      </div>
      <!--    轮播图-->
      <div style="flex: 1; margin: 10px 0 0 ">
        <span class="demonstration"></span>
        <el-carousel trigger="click" height="400px">
          <el-carousel-item v-for="item in list" :key="item">
            <img :src="item.img" >
          </el-carousel-item>
        </el-carousel>
      </div>
    </div>

    <div style="width: 100px; height: 50px; text-align: center; margin:25px 0 0 710px">
      <a style="font-size: 28px; font-weight: bold; padding-top: 100px">手机</a>
    </div>
    <div style="margin: 10px 60px; background-color: whitesmoke; height: 640px; width: 1400px; ">
      <el-row :gutter="12" >
        <el-col :span="4"  v-for="item in tableData" :key="item.id">
            <div class="phone">
              <img :src="item.url" alt="" @click="$router.push('/detail?id=' + item.id)" style="width: 140px; height: 140px; margin-top: 5px; margin-left: 2px; cursor: pointer">
              <div class="refer" @click="$router.push('/detail?id=' + item.id)"><b>{
   
   {item.refer}}</b></div>
              <div class="goodsName" @click="$router.push('/detail?id=' + item.id)">{
   
   {item.name}}</div>
              <div class="price" @click="$router.push('/detail?id=' + item.id)">¥{
   
   {item.price}}</div>
            </div>
        </el-col>
      </el-row>
    </div>
    <div style="padding: 10px 0 0 50px">
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="pageNum"
          :page-sizes="[ 5, 10, 15]"
          :page-size="pageSize"
          layout="total, prev, pager, next"
          :total="total">
      </el-pagination>
    </div>

<!--    <div style="width: 100%; height: 50px; margin-top: 50px">-->
<!--      <a style="font-size: 28px; font-weight: bold; margin-left: 730px">电脑</a>-->
<!--    </div>-->
<!--    <div style="margin: 10px 60px; background-color: whitesmoke; height: 640px; width: 1400px; ">-->
<!--      <el-row :gutter="10" >-->
<!--        <el-col :span="4"  v-for="item in tableData" :key="item.id">-->
<!--          <div class="phone">-->
<!--            <img :src="item.url" alt="" @click="$router.push('/detail?id=' + item.id)" style="width: 170px; height: 170px; margin-top: 5px; margin-left: 3px; cursor: pointer">-->
<!--            <div class="refer" @click="$router.push('/detail?id=' + item.id)"><b>{
   
   {item.refer}}</b></div>-->
<!--            <div class="goodsName" @click="$router.push('/detail?id=' + item.id)">{
   
   {item.name}}</div>-->
<!--            <div class="price" @click="$router.push('/detail?id=' + item.id)">¥{
   
   {item.price}}</div>-->
<!--          </div>-->
<!--        </el-col>-->
<!--      </el-row>-->
<!--    </div>-->
<!--    <div style="width: 100%; height: 50px; margin-top: 50px">-->
<!--      <a style="font-size: 28px; font-weight: bold; margin-left: 705px">电脑外设</a>-->
<!--    </div>-->
<!--    <div style="margin: 10px 60px; background-color: whitesmoke; height: 640px; width: 1400px; ">-->
<!--      <el-row :gutter="10" >-->
<!--        <el-col :span="4"  v-for="item in tableData" :key="item.id">-->
<!--          <div class="phone">-->
<!--            <img :src="item.url" alt="" @click="$router.push('/detail?id=' + item.id)" style="width: 170px; height: 170px; margin-top: 5px; margin-left: 3px; cursor: pointer">-->
<!--            <div class="refer" @click="$router.push('/detail?id=' + item.id)"><b>{
   
   {item.refer}}</b></div>-->
<!--            <div class="goodsName" @click="$router.push('/detail?id=' + item.id)">{
   
   {item.name}}</div>-->
<!--            <div class="price" @click="$router.push('/detail?id=' + item.id)">¥{
   
   {item.price}}</div>-->
<!--          </div>-->
<!--        </el-col>-->
<!--      </el-row>-->
<!--    </div>-->
<!--    <div style="width: 100%; height: 50px; margin-top: 50px">-->
<!--      <a style="font-size: 28px; font-weight: bold; margin-left: 705px">电脑配件</a>-->
<!--    </div>-->
<!--    <div style="margin: 10px 60px; background-color: whitesmoke; height: 640px; width: 1400px; ">-->
<!--      <el-row :gutter="10" >-->
<!--        <el-col :span="4"  v-for="item in tableData" :key="item.id">-->
<!--          <div class="phone">-->
<!--            <img :src="item.url" alt="" @click="$router.push('/detail?id=' + item.id)" style="width: 170px; height: 170px; margin-top: 5px; margin-left: 3px; cursor: pointer">-->
<!--            <div class="refer" @click="$router.push('/detail?id=' + item.id)"><b>{
   
   {item.refer}}</b></div>-->
<!--            <div class="goodsName" @click="$router.push('/detail?id=' + item.id)">{
   
   {item.name}}</div>-->
<!--            <div class="price" @click="$router.push('/detail?id=' + item.id)">¥{
   
   {item.price}}</div>-->
<!--          </div>-->
<!--        </el-col>-->
<!--      </el-row>-->
<!--    </div>-->
    <div style="width: 100%; height: 250px; margin-top: 80px">
      <div style="height: 250px;width: 1510px; background-color: #545c64">
          <h3 style="margin-left: 705px; font-size: 28px; color: white">合作伙伴</h3>
          <img src="src/assets/images/footer/facebook.png" alt="" style="width: 30px; height: 30px; margin-left: 665px">
          <img src="src/assets/images/footer/推特.png" alt="" style="width: 30px; height: 30px; margin-left: 10px">
          <img src="src/assets/images/footer/telegram.png" alt="" style="width: 30px; height: 30px; margin-left: 10px">
          <img src="src/assets/images/footer/xbox.png" alt="" style="width: 30px; height: 30px; margin-left: 10px">
          <img src="src/assets/images/footer/Youtube.png" alt="" style="width: 30px; height: 30px; margin-left: 10px">
        <div style="margin-top: 15px">
          <a style="margin-left: 280px; font-size: 16px; color: white">商城 | 游戏 | 政企服务 | 集团隐私政策 | 公司儿童信息保护规则 | 商城隐私政策 | 商城用户协议 | 问题反馈 | Select Location</a>
        </div>
        <div style="margin-top: 10px">
          <a style="margin-left: 315px;font-size: 16px; color: white"> 互联网ICP备案:沪ICP备13002172号-3 沪-非经营性-2016-0143 营业性演出许可证 沪市文演(经)00-2253 | </a>
        </div>
      </div>

    </div>
  </div>
</template>

<script>

export default {
  name: "Home",
  components: {},
  data() {
    return {
      tableData: [],
      total: 0,
      pageNum: 1,
      pageSize: 10,
      name: "",
      user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {},
      list:[
        {img:require('../../assets/images/Carousel/img.png')},
        {img:require('../../assets/images/Carousel/img_1.png')},
        {img:require('../../assets/images/Carousel/img_2.png')},
        {img:require('../../assets/images/Carousel/img_3.png')},
        {img:require('../../assets/images/Carousel/img_4.png')},
      ]
    }
  },
  created() {
    this.load()
  },
  methods: {
    load: function () {
      this.request.get("/goods/page", {
        params: {
          pageNum: this.pageNum,
          pageSize: this.pageSize,
          name: this.name,
        }
      }).then(res => {
        this.tableData = res.data.records
        this.total = res.data.total
      })
    },
    home() {
      this.$router.push("/")
    },
    handleSizeChange(pageSize) {
      console.log(pageSize)
      this.pageSize = pageSize
      this.load()
    },
    handleCurrentChange(pageNum) {
      console.log(pageNum)
      this.pageNum = pageNum
      this.load()
    },
  }
}
</script>

<style scoped>
li:hover {
  color: orangered;
}
.goodsName {
  font-size: 14px;
  text-align: center;
  cursor: pointer
}
.price {
  font-size: 16px;
  font-weight: bold;
  color: orangered;
  cursor: pointer;
}
.refer {
  padding: 2px;
  cursor: pointer;
  /*margin-top: 5px;*/
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.base {
  margin: 0px;
  padding: 0px;
}
img {
  width: 100%;
  height: 100%;
}
.phone {
  background-color: white;
  padding-bottom: 10px;
  font-size: 16px;
  text-align: center;
  width: 160px;
  height: 150px;
  transition: all 0.8s;
  margin: 60px 16px;
}
.box~.phone{
  margin-left: 30px;
}
.box0 img{
  width: 170px;
  height: 170px;
}
.phone:hover{
  transform: scale(1.08);
}

</style>

 Product details page:

 Source codeDetail.Vue

<template>
  <div style="padding: 10px 0">
    <el-card style="width: 1100px; margin-left: 200px">
      <div style="display: flex">
        <div style="width: 350px">
          <el-image :src="goods.url" :preview-src-list="[goods.url]" style="width: 80%; position: center; margin-top: 30px"></el-image>
        </div>
        <div style="flex: 1; padding-left: 50px">
          <div class="goodsName">{
   
   { goods.name }}</div>
          <div class="refer">{
   
   { goods.refer }}</div>
          <div class="price">¥{
   
   { goods.price }}</div>
          <div class="refer" style="margin-top: 10px;">库存{
   
   { goods.num }}台</div>
          <div class="goodsName">
            <el-input-number size="big" v-model="form.number" :min="1" :max="100" label="数量"></el-input-number>
          </div>
          <div class="goodsName" >
<!--            <template v-slot="scope">-->
              <el-button class="addCar" size="big" @click="buy(scope.row.id)"><i class="el-icon-bank-card"/> 直接购买</el-button>
              <el-button class="addCar" size="big" v-on:click="addCart"><i class="el-icon-shopping-cart-1" /> 加入购物车</el-button>
<!--            </template>-->
          </div>
          <a size="big" @click="chat" style="float: left; color: #DF3033; cursor: pointer; padding-left: 10px">联系商家</a>
        </div>
      </div>
    </el-card>
  </div>
</template>

<script>
import {serverIp} from "../../../public/config";

const baseUrl = `http://${serverIp}:9090`
export default {
  name: "Detail",
  data() {
    return {
      id: this.$route.query.id,
      goods: {},
      form: {number: 1},
      user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
    }
  },
  created() {
    this.load()
  },
  methods: {
    load() {
      this.request.get("/goods/" + this.id).then(res => {
        this.goods = res.data
      })
    },
    chat() {
      this.$router.push("/im")
    },
    addCart() {
      if (!this.user.username) {
        this.$message.warning("请登录后操作")
        return
      }
      this.form.goodsId = this.goods.id  //商品ID
      this.request.post("/cart", this.form).then(res => {
        if (res.code === '200') {
          this.$message.success("加入购物车成功")
        } else {
          this.$message.error(res.msg)
        }
      })
    },
    buy(goodsId) {
      fetch(baseUrl + '/api/buy?goodsId=' + goodsId, {
        headers: {
          'Content-Type': 'application/json;charset=utf-8'
        },
        method: 'POST'
      }).then(res => res.json()).then(res => {
        if (res) {
          this.$message.success("下单成功")
          this.load()
        } else {
          this.$message.error("下单失败")
        }
      })
    }
  }
}
</script>

<style scoped>
.addCar {
  padding: 10px;
  /*margin-left: 10px;*/
  width: 140px;
  height: 45px;
  background-color: #DF3033;
  color: white;
  font-weight: bold;
  font-size: 18px
}
.goodsName {
  padding: 10px;
  font-size: 22px;
  font-weight: bold;
}
.refer {
  padding: 10px;
  font-size: 16px;
  font-weight: bold
}
.price {
  height: 60px;
  padding: 15px 10px 10px 20px;
  background-color: #FCE5E5;
  color: orangered;
  font-weight: bold;
  margin-left: 10px;
  margin-top: 10px;
  font-size: 24px;
}
</style>

my shopping cart: 

You can check the items to calculate the price, and then go to the order page to pay for the item settlement, or you can choose to delete the items in the shopping cart.

My Order:

You can check the items in your order, and set the time to automatically close after 5 seconds. Payment is made using the Alipay sandbox. You cannot make a second payment for an order that has already been paid. Even if you pay, an error will be reported, and you cannot cancel an order that has already been paid.

return data:

Alipay stores the callback information in the database, and the background can receive the information. 

After the payment is made, the order can be shipped in the background, and the user can also see whether the order status has been shipped in my order, so as to perform the receiving operation.

personal information:

 Source codePerson.vue

<template>
  <el-card style="width: 500px; margin-left: 50px">
    <el-form label-width="80px" size="small">
      <el-form-item label="用户名">
        <el-input v-model="form.username" disabled autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="昵称">
        <el-input v-model="form.nickname" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="性别">
        <el-input v-model="form.sex" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="邮箱">
        <el-input v-model="form.email" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="电话">
        <el-input v-model="form.phone" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="地址">
        <el-input type="textarea" v-model="form.address" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="save">保 存</el-button>
        <el-button type="primary" @click="sign" disabled><i class="el-icon-location" />定位</el-button>
        <el-button type="success" @click="return1" style="float: right">返回主页</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script>

export default {
  name: "Person",
  data() {
    return {
      form: {},
      user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
    }
  },
  mounted() {

    // 获取地理位置
    var geolocation = new BMapGL.Geolocation();
    geolocation.getCurrentPosition(function(r){
      if(this.getStatus() == BMAP_STATUS_SUCCESS){
        const province = r.address.province
        const city = r.address.city
        localStorage.setItem("address", province + city)
      }
    });
  },
  created() {
    this.request.get("/user/username/" + this.user.username).then(res => {
      if (res.code === '200') {
        this.form = res.data
      }
    })
  },
  methods: {
    sign() {
      const address = localStorage.getItem("address")
      const username = this.user.username

      this.request.post("/user", { user: username, address: address }).then(res => {
        if (res.code === '200') {
          this.$message.success("获取成功")
        } else {
          this.$message.error(res.msg)
        }
      })
    },
    save() {
      this.request.post("/user", this.form).then(res => {
        if (res.data) {
          this.$message.success("保存成功")
        } else {
          this.$message.error("保存失败")
        }
      })
    },
    return1() {
      this.$router.push("/")
    }
  }
}
</script>

<style>

</style>

Contact the merchant:

For this function, you can refer to my other article: (2 messages) SpringBoot implements a simple chat room_Mu Yan wants to work hard-CSDN Blog

 Background page:

Core code: 

1.UserController

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.Constants;
import com.example.demo.common.Result;
import com.example.demo.controller.dto.UserDTO;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import com.example.demo.utils.TokenUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    @PostMapping("/login")
    public Result login(@RequestBody UserDTO userDTO) {
        String username = userDTO.getUsername();
        String password = userDTO.getPassword();
        if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
            return Result.error(Constants.CODE_400,"参数错误");
        }
        UserDTO dto = userService.login(userDTO);
        return Result.success(dto);
    }

    @PostMapping("/register")
    public Result register(@RequestBody UserDTO userDTO) {
        String username = userDTO.getUsername();
        String password = userDTO.getPassword();
        if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
            return Result.error(Constants.CODE_400,"参数错误");
        }
        return Result.success(userService.register(userDTO));
    }

    //新增或者更新
    @PostMapping
    public Result save(@RequestBody User user) {
        return Result.success(userService.saveOrUpdate(user));
    }

    //删除
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        return Result.success(userService.removeById(id));
    }

    @PostMapping("/del/batch")
    public Result deleteBatch(@RequestBody List<Integer> ids) {//批量删除
        return Result.success(userService.removeByIds(ids));
    }

    //    //查询所有数据
//    @GetMapping
//    public Result findAll() {
//        return Result.success(userService.list());
//    }
//
    @GetMapping("/{id}")
    public Result findOne(@PathVariable Integer id) {
        return Result.success(userService.getById(id));
    }

    @GetMapping("/username/{username}")
    public Result findOne(@PathVariable String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        return Result.success(userService.getOne(queryWrapper));
    }

    @GetMapping("/page")
    public Result findPage(@RequestParam Integer pageNum,
                           @RequestParam Integer pageSize,
                           @RequestParam(defaultValue = "") String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        if (!"".equals(username)) {
            queryWrapper.like("username", username);
        }
        return Result.success(userService.page(new Page<>(pageNum, pageSize), queryWrapper));

    }

}

2.TokenUtils 

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Component
public class TokenUtils {

    private static IUserService staticUserService;

    @Resource
    private IUserService userService;

    @PostConstruct
    public void setUserService() {
        staticUserService = userService;
    }

    /**
     * 生成token
     *
     * @return
     */
    public static String genToken(String userId, String sign) {
        return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
                .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期
                .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
    }

    /**
     * 获取当前登录的用户信息
     *
     * @return user对象
     */
    public static User getCurrentUser() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String token = request.getHeader("token");
            if (StrUtil.isNotBlank(token)) {
                String userId = JWT.decode(token).getAudience().get(0);
                return staticUserService.getById(Integer.valueOf(userId));
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }
}

3.CartController

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.Result;
import com.example.demo.entity.Cart;
import com.example.demo.entity.User;
import com.example.demo.mapper.CartMapper;
import com.example.demo.service.ICartService;
import com.example.demo.utils.TokenUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

@CrossOrigin
@RestController
@RequestMapping("/cart")
public class CartController {

    @Resource
    private ICartService cartService;

    @Resource
    private CartMapper cartMapper;

    //新增或者更新
    @PostMapping
    public Result save(@RequestBody Cart cart) {
        Integer userId = TokenUtils.getCurrentUser().getId();
        //相同商品进行处理
        Integer goodsId = cart.getGoodsId();
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("goods_id", goodsId);
        queryWrapper.eq("user_id", userId);

        Cart db = cartService.getOne(queryWrapper);
        if (db != null) {
//            db.setNumber(db.getNumber() + cart.getNumber());
            db.setNumber(db.getNumber() + cart.getNumber());
            cartService.updateById(db);
            return Result.success();
        }
        //新增或更新
        if (cart.getId() == null) {
            cart.setUserId(userId);
        }
        cartService.saveOrUpdate(cart);
        return Result.success();
    }

    @PostMapping("/number/{id}/{number}")
    public Result updateNum(@PathVariable Integer id, @PathVariable Integer number) {
        cartMapper.updateNum(number, id);
        return Result.success();
    }

    //删除
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        return Result.success(cartService.removeById(id));
    }

    @PostMapping("/del/batch")
    public Result deleteBatch(@RequestBody List<Integer> ids) {//批量删除
        return Result.success(cartService.removeByIds(ids));
    }

    //查询所有数据
    @GetMapping
    public Result findAll() {
        return Result.success(cartService.list());
    }

    @GetMapping("/{id}")
    public Result findOne(@PathVariable Integer id) {
        return Result.success(cartService.getById(id));
    }

//    @GetMapping("/id/{id}")
//    public Result findOne(@PathVariable String userId) {
//        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("userId", userId);
//        return Result.success(cartService.getOne(queryWrapper));
//    }

    @GetMapping("/page")
    public Result findPage(@RequestParam Integer pageNum,
                           @RequestParam Integer pageSize,
                           @RequestParam(defaultValue = "") String name) {
        User currentUser = TokenUtils.getCurrentUser();
        Integer userId = currentUser.getId();
        String role = currentUser.getRole();

        return Result.success(cartMapper.page(new Page<>(pageNum, pageSize), userId, role, name));
    }

}

4.EchartsController

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Quarter;
import com.example.demo.common.Result;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/echarts")
public class EchartsController {

    @Autowired
    private IUserService userService;

    @GetMapping("/example")
    public Result get() {
        Map<String, Object> map = new HashMap<>();
        map.put("x", CollUtil.newArrayList("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"));
        map.put("y", CollUtil.newArrayList(150, 230, 224, 218, 135, 147, 260));
        return Result.success(map);
    }

    @GetMapping("/members")
    public Result members() {
        List<User> list = userService.list();
        int q1 = 0;  //第一季度
        int q2 = 0;  //第二季度
        int q3 = 0;  //第三季度
        int q4 = 0;  //第四季度
        for (User user : list) {
            Date createTime = user.getCreateTime();
            Quarter quarter = DateUtil.quarterEnum(createTime);
            switch (quarter) {
                case Q1: q1 += 1; break;
                case Q2: q2 += 1; break;
                case Q3: q3 += 1; break;
                case Q4: q4 += 1; break;
                default: break;
            }
        }
        return Result.success(CollUtil.newArrayList(q1, q2, q3, q4));
    }
}

5.FileController

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.Files;
import com.example.demo.entity.Goods;
import com.example.demo.mapper.FileMapper;
import com.example.demo.mapper.GoodsMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

@RestController
@RequestMapping("/file")
public class FileController {

    @Value("${files.upload.path}")
    private String fileUploadPath;

    @Value("${server.ip}")
    private String serverIp;

    @Resource
    private FileMapper fileMapper;

    @Resource
    private GoodsMapper goodsMapper;

    @PostMapping("/upload")
    public String upload(@RequestParam MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        String type = FileUtil.extName(originalFilename);
        long size = file.getSize();

        //定义一个文件的唯一标识码
//        String uuid = IdUtil.fastSimpleUUID();
//        String fileUUID = uuid + StrUtil.DOT + type;

//        File uploadFile = new File(fileUploadPath + fileUUID);
        //先存储到磁盘
        File parentFile = new File(fileUploadPath);
//        File parentFile = uploadFile.getParentFile();
        //判断目录是否存在,不存在就新建
        if (!parentFile.exists()) {
             parentFile.mkdirs();
        }
        String uuid = IdUtil.fastSimpleUUID();
        String fileUUID = uuid + StrUtil.DOT + type;
        File uploadFile = new File(fileUploadPath + fileUUID);

        file.transferTo(uploadFile);
        String url = "http://" + serverIp + ":9090/file/" + fileUUID;
        //存储到数据库
        Files saveFile = new Files();
        Goods goods = new Goods();
        saveFile.setName(originalFilename);
        saveFile.setType(type);
        saveFile.setSize(size/1024);
        saveFile.setUrl(url);
        goods.setUrl(url);
        fileMapper.insert(saveFile);
        goodsMapper.insert(goods);
        return url;

//        String md5 = SecureUtil.md5(file.getInputStream());
//        Files files = getFileByMd5(md5);
//
//        String url;
//        if (files != null) {
//            url = files.getUrl();
//        } else {
//            file.transferTo(uploadFile);
//            url = "http://localhost:9090/file/" + fileUUID;
//        }
//        //存储到数据库
//        Files saveFile = new Files();
//        saveFile.setName(originalFilename);
//        saveFile.setType(type);
//        saveFile.setSize(size/1024);
//        saveFile.setUrl(url);
//        saveFile.setMd5(md5);
//        fileMapper.insert(saveFile);
//        return url;
    }

    @GetMapping("/{fileUUID}")
    public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
        // 根据文件的唯一标识码获取文件
        File uploadFile = new File(fileUploadPath + fileUUID);
        // 设置输出流的格式
        ServletOutputStream os = response.getOutputStream();
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));
        response.setContentType("application/octet-stream");

        // 读取文件的字节流
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }

    /**
     * 通过文件的md5查询文件
     * @param md5
     * @return
     */
    private Files getFileByMd5(String md5) {
        // 查询文件的md5是否存在
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5", md5);
        List<Files> filesList = fileMapper.selectList(queryWrapper);
        return filesList.size() == 0 ? null : filesList.get(0);
    }
}

6.MybatisPlusConfig

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.example.demo.mapper")
public class MybatisPlusConfig {
    /**
     * 分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

7.Constants

public interface Constants {

    String CODE_200 = "200"; //成功
    String CODE_400 = "400"; //参数不足
    String CODE_401 = "401"; //权限不足
    String CODE_500 = "500"; //系统错误
    String CODE_600 = "600"; //其他业务异常
}

Ending Sahua, for the online mall project, there will definitely be a lot of optimizations. I also have two versions of this project, the one on the server and the one not on the server, but they are basically the same. The basic functions can also be realized, but it must be almost meaningless compared with commercial ones. Dear friends, if you think the author's writing is not bad, please like it a lot. If you need the source code, you can also private message me. I will reply you as soon as I see the information. Remember to like and follow! ! ! !

Guess you like

Origin blog.csdn.net/weixin_65950231/article/details/128560313