Springboot3 + MyBatis-Plus + MySql + Vue + ProTable + TS 实现后台管理商品分类(最新教程附源码)-后端源码

时间:2024-10-01 08:25:54

3.1 application.yml 方便 AliOssUtil.java 读取

server:
  port: 8080
spring:
  servlet:
    multipart:
      max-file-size: 40MB
      max-request-size: 40MB
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://localhost:3306/yunshangshequ?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2b8
    username: root
    password: 123456
    hikari:
      connection-test-query: SELECT 1 # 自动检测连接
      connection-timeout: 60000 #数据库连接超时时间,默认30秒
      idle-timeout: 500000 #空闲连接存活最大时间,默认600000(10分钟)
      max-lifetime: 540000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
      maximum-pool-size: 12 #连接池最大连接数,默认是10
      minimum-idle: 10 #最小空闲连接数量
      pool-name: SPHHikariPool # 连接池名称
  jackson:
    time-zone: GMT+8

  data:
    redis:
      host: localhost
      port: 6379
      database: 0
#用于打印框架生成的sql语句,便于调试
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      logic-delete-field: isDeleted # 全局逻辑删除的实体字段名
      logic-delete-value: 1   # 逻辑已删除的值 默认为 1
      logic-not-delete-value: 0 # 逻辑未删除的值  默认为 0

minio:
  endpoint: http://localhost:9000
  access-key: minioadmin
  secret-key: minioadmin
  bucket-name: yunshangshequ
springdoc:
  default-flat-param-object: true

alioss: # 阿里云配置
  endpoint: "https://cn-chengdu.oss.aliyuncs.com"    # Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
  bucketName: ""  # 填写Bucket名称,例如examplebucket。
  access_key: ""  # 点击头像->Accesskey管理查看 秘钥
  access_key_secret: "" # 密码

3.2 model 层

3.2.1 BaseEntity


package com.zhong.model.entity;


import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
public class BaseEntity implements Serializable {

    @Schema(description = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @Schema(description = "创建时间")
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    @JsonIgnore
    private Date createTime;

    @Schema(description = "更新时间")
    @TableField(value = "update_time", fill = FieldFill.UPDATE)
    @JsonIgnore
    private Date updateTime;

    @Schema(description = "逻辑删除")
    @TableField("is_deleted")
    @JsonIgnore
    private Byte isDeleted;

}

3.2.1 GoodsType


package com.zhong.model.entity.goods;

import com.zhong.model.entity.BaseEntity;
import lombok.Data;

/**
 * 商品分类
 * @TableName shop_type
 */
@Data
public class GoodsType extends BaseEntity {

    /**
     /**
     * 分类名称
     */
    private String name;

    /**
     * 分类描述
     */
    private String description;
    /**
     * 排序值
     */
    private Long typeSort;
    /**
     * 分类图标
     */
    private String img;

    /**
     * 如果没有 father_id 则是一级分类
     */
    private Integer fatherId;

    /**
     * 是否启用 1 启用 0禁用
     */
    private Integer status;

    private static final long serialVersionUID = 1L;
}

3.2.3 GoodsTypeSonVo


package com.zhong.vo.small;

import com.zhong.model.entity.goods.GoodsType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.List;

/**
 * @ClassName : GoodsTypeVo
 * @Description :
 * @Author : zhx
 * @Date: 2024-09-29 15:08
 */
@Data
public class GoodsTypeSonVo {
   List<GoodsType> fatherType;
   List<GoodsType> sonType;
}

3.3 Controller 层

3.3.1 FileUploadController.java 后端上传图片到阿里云OSS


package com.zhong.controller.apartment;

import com.zhong.result.Result;
import com.zhong.utils.AliOssUtil;
import io.minio.errors.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;


@Tag(name = "文件管理")
@RequestMapping("/admin/file")
@RestController
public class FileUploadController {

    @Autowired
    private AliOssUtil ossUtil;

    @Operation(summary = "上传文件")
    @PostMapping("/upload")
    public Result<String> upload(@RequestParam MultipartFile file) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        // 获取文件原名
        String originalFilename = file.getOriginalFilename();
        // 防止重复上传文件名重复
        String fileName = null;
        if (originalFilename != null) {
            fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.indexOf("."));
        }
        // 把文件储存到本地磁盘
//        file.transferTo(new File("E:\\SpringBootBase\\ProjectOne\\big-event\\src\\main\\resources\\flies\\" + fileName));
        String url = ossUtil.uploadFile(fileName, file.getInputStream());
        System.out.println();
        return Result.ok(url);
    }
}

3.3.2 AliOssUtil.java 后端上传图片到阿里云OSS的工具类


package com.zhong.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.zhong.result.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @ClassName : AliOssUtil
 * @Description : 阿里云上传服务
 * @Author : zhx
 * @Date: 2024-03-1 20:29
 */
@Component
@Service
public class AliOssUtil {
    @Value("${alioss.endpoint}")
    private String ENDPOINT;

    @Value("${alioss.bucketName}")
    private String BUCKETNAME;

    @Value("${alioss.access_key}")
    private String ACCESS_KEY;

    @Value("${alioss.access_key_secret}")
    private String ACCESS_KEY_SECRET;

    public String uploadFile(String objectName, InputStream inputStream) {
        String url = "";
        // 创建OSSClient实例。
        System.out.println(ACCESS_KEY);
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_KEY_SECRET);
        try {
            // 创建PutObjectRequest对象。
            // 生成日期文件夹路径,例如:2022/04/18
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");
            String dateStr = dateFormat.format(new Date());
            PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, dateStr + "/" + objectName, inputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);

            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);

            url = "https://" + BUCKETNAME + "." + ENDPOINT.substring(ENDPOINT.lastIndexOf("/") + 1) + "/" + dateStr + "/" + objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return url;
    }

    public  Result deleteFile(String objectName) {
        System.out.println(objectName);
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_KEY_SECRET);
        try {
            // 删除文件。
            System.out.println(objectName);
            System.out.println(objectName.replace(",", "/"));
            ossClient.deleteObject(BUCKETNAME, objectName.replace(",", "/"));
            return Result.ok("删除成功!");
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return Result.fail(555,"上传失败!");
    }
}

3.3.3 GoodsTypeController.java 商品分类接口


package com.zhong.controller.small;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhong.model.entity.enums.BaseStatus;
import com.zhong.model.entity.goods.GoodsType;
import com.zhong.result.Result;
import com.zhong.service.small.GoodsTypeService;
import com.zhong.vo.small.GoodsTypeSonVo;
import com.zhong.vo.small.GoodsTypeVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @ClassName : ShopSpecsController
 * @Description :  商品分类
 * @Author : zhx
 * @Date: 2024-09-28 15:07
 */
@Slf4j
@RestController
@Tag(name = "后台商品分类管理")
@RequestMapping("/admin/goods/type")
public class GoodsTypeController {

    @Autowired
    private GoodsTypeService service;

    @Operation(summary = "分页获商品分类信息")
    @GetMapping("page")
    private Result<IPage<GoodsType>> page(@RequestParam long current, @RequestParam long size, GoodsTypeVo goodsTypeVo) {
        Page<GoodsType> goodsTypePage = new Page<>(current, size);
        Page<GoodsType> page = service.pageItem(goodsTypePage, goodsTypeVo);
        return Result.ok(page);
    }

    @Operation(summary = "获所有商品二级分类信息")
    @GetMapping("page/son")
    private Result<GoodsTypeSonVo> pageSon(@RequestParam long id) {
        GoodsTypeSonVo page = service.list(id);
        return Result.ok(page);
    }

    @Operation(summary = "获所有商品分类信息")
    @GetMapping("list")
    private Result<List<GoodsType>> page() {
        List<GoodsType> page = service.list();
        return Result.ok(page);
    }

    @Operation(summary = "根据ID修改商品分类")
    @PostMapping("saveOrUpdate")
    public Result saveOrUpdateType(@RequestBody GoodsType goodsType) {
        goodsType.setIsDeleted((byte) 0);
        service.saveOrUpdate(goodsType);
        return Result.ok();
    }

    @DeleteMapping("deleteById")
    @Operation(summary = "根据id删除商品分类")
    public Result removeById(@RequestParam Long id) {
        service.removeById(id);
        return Result.ok();
    }

}

3.4 GoodsTypeService 层


package com.zhong.service.small;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zhong.model.entity.goods.GoodsType;
import com.zhong.vo.small.GoodsTypeSonVo;
import com.zhong.vo.small.GoodsTypeVo;

import java.util.List;

/**
* @author zhong
* @description 针对表【shop_type(商品分类)】的数据库操作Service
* @createDate 2024-09-15 18:18:13
*/
public interface GoodsTypeService extends IService<GoodsType> {

    Page<GoodsType> pageItem(Page<GoodsType> goodsTypePage, GoodsTypeVo goodsTypeVo);

    GoodsTypeSonVo list(long id);

}

3.5 GoodsTypeServiceImpl 层


package com.zhong.service.small.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.zhong.mapper.small.GoodsTypeMapper;
import com.zhong.model.entity.goods.GoodsSku;
import com.zhong.model.entity.goods.GoodsType;
import com.zhong.service.small.GoodsTypeService;
import com.zhong.vo.small.GoodsTypeSonVo;
import com.zhong.vo.small.GoodsTypeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author zhong
 * @description 针对表【shop_type(商品分类)】的数据库操作Service实现
 * @createDate 2024-09-15 18:18:13
 */
@Service
public class GoodsTypeServiceImpl extends ServiceImpl<GoodsTypeMapper, GoodsType>
        implements GoodsTypeService {

    @Autowired
    private GoodsTypeMapper mapper;

    @Override
    public Page<GoodsType> pageItem(Page<GoodsType> goodsTypePage, GoodsTypeVo goodsTypeVo) {
        LambdaQueryWrapper<GoodsType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNull(GoodsType::getFatherId)
                .eq(GoodsType::getIsDeleted, 0);
        if (goodsTypeVo.getName() != null) {
            queryWrapper.like(GoodsType::getName, goodsTypeVo.getName());
        }
        if (goodsTypeVo.getId() != null) {
            queryWrapper.like(GoodsType::getId, goodsTypeVo.getId());
        }
        queryWrapper.orderByDesc(GoodsType::getTypeSort);
        return mapper.selectPage(goodsTypePage, queryWrapper);
    }

    @Override
    public GoodsTypeSonVo list(long id) {
        GoodsTypeSonVo goodsTypeSonVo = new GoodsTypeSonVo();

        // 获取父分类
        LambdaQueryWrapper<GoodsType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GoodsType::getIsDeleted, 0)
                .eq(GoodsType::getId, id);
        List<GoodsType> goodsTypes = mapper.selectList(queryWrapper);
        goodsTypeSonVo.setFatherType(goodsTypes);

        // 获取子分类
        LambdaQueryWrapper<GoodsType> sonQueryWrapper = new LambdaQueryWrapper<>();
        sonQueryWrapper.eq(GoodsType::getIsDeleted, 0)
                .eq(GoodsType::getFatherId, id)
                .orderByDesc(GoodsType::getTypeSort);
        List<GoodsType> sonGoodsTypes = mapper.selectList(sonQueryWrapper);
        goodsTypeSonVo.setSonType(sonGoodsTypes);

        return goodsTypeSonVo;
    }
}