乐优商城项目总结——06商品新增(图片上传FastDFS等)

品牌新增

新增的功能实现就是填写spu数据,传入到数据库,不过这里还涉及到了图片,需要上传到linux里的FastDFS。

实体类

spu的实体类有一点区别

  1. @JsonIgnore他可以返回数据到页面的时候不返回这些,忽略这些字段。
  2. @Transient 加上这个注释,就不会持久化到数据库中,因为spu的表中没有这些字段,这些数据需要到存到其他表中,但是传入的时候传入多个对象接收不方便,我们可以在spu中加入这些字段,存的时候拿出来存到它该去的地方,但是不存到tb_spu的表中。
@Data
@Table(name = "tb_spu")
public class Spu {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long brandId;
    private Long cid1;// 1级类目
    private Long cid2;// 2级类目
    private Long cid3;// 3级类目
    private String title;// 标题
    private String subTitle;// 子标题
    private Boolean saleable;// 是否上架
    @JsonIgnore
    private Boolean valid;// 是否有效,逻辑删除用
    private Date createTime;// 创建时间
    @JsonIgnore //返回页面时候忽略这个字段
    private Date lastUpdateTime;// 最后修改时间
//        @Transient不持久化到数据库
    @Transient
    private String canme;
    @Transient
    private String banme;
    @Transient
    private List<Sku> skus;
    @Transient
    private SpuDetail spuDetail;
}
service

实现并不是太难,只不过有点多。
并且操作太多,要加上事务进行控制。

 /**
     * 新增商品
     *
     * @param spu
     */
    @Transactional
    public void saveGoods(Spu spu) {
        //新增spu
        spu.setId(null);
        spu.setCreateTime(new Date());
        spu.setLastUpdateTime(spu.getCreateTime());
        spu.setSaleable(true);
        spu.setValid(false);
        int insert = spuMapper.insert(spu);
        if (insert != 1) {
            throw new RuntimeException("新增商品失败!");
        }
        //新增detail
        SpuDetail spuDetail = spu.getSpuDetail();
        spuDetail.setSpuId(spu.getId());
        spuDetailMapper.insert(spuDetail);
        //定义库存集合,增加效率
        List<Stock> stockList = new ArrayList<>();
        //新增sku
        List<Sku> skus = spu.getSkus();

        for (Sku sku : skus) {
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(sku.getCreateTime());
            sku.setSpuId(spu.getId());
            int insert1 = skuMapper.insert(sku);
            if (insert1 != 1) {
                throw new RuntimeException("新增商品失败!");
            }
            //新增库存
            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock());
            stockList.add(stock);
        }
        //批量新增库存
        int list = stockMapper.insertList(stockList);
        if (list != stockList.size()) {
            throw new RuntimeException("新增商品失败!");
        }
    }

图片的上传

文件的上传并不只是在品牌管理中有需求,以后的其它服务也可能需要,因此我们创建一个独立的微服务,专门处理各种上传(但其实这个项目就弄了这一个上传的项目)。

FastDFS简介

分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。

通俗来讲:

  • 传统文件系统管理的文件就存储在本机。
  • 分布式文件系统管理的文件存储在很多机器,这些机器通过网络连接,要被统一管理。无论是上传或者访问文件,都需要通过管理中心来访问。

FastDFS架构图:
在这里插入图片描述
FastDFS两个主要的角色:Tracker ServerStorage Server

  • Tracker Server:跟踪服务器,主要负责调度storage节点与client通信,在访问上起负载均衡的作用,和记录storage节点的运行状态,是连接client和storage节点的枢纽。
  • Storage Server:存储服务器,保存文件和文件的meta data(元数据),每个storage server会启动一个单独的线程主动向Tracker cluster中每个tracker server报告其状态信息,包括磁盘使用情况,文件同步情况及文件上传下载次数统计等信息
  • Group:文件组,多台Storage Server的集群。上传一个文件到同组内的一台机器上后,FastDFS会将该文件即时同步到同组内的其它所有机器上,起到备份的作用。不同组的服务器,保存的数据不同,而且相互独立,不进行通信。
  • Tracker Cluster:跟踪服务器的集群,有一组Tracker Server(跟踪服务器)组成。
  • Storage Cluster :存储集群,有多个Group组成。

自己感觉就跟Eureka注册中心差不多,
你存的时候有Tracker Server管理,它来决定你存到那里,存的地方就叫Storage Server。
你取的时候Tracker Server找存在了哪个Storage Server。
然后那一个个的都是Storage Server备份,不能挂了一个然后存的东西丢了。

创建上传微服务

FastDFS的pom依赖:

 <dependency>
        <groupId>com.github.tobato</groupId>
        <artifactId>fastdfs-client</artifactId>
    </dependency>

yml文件中配置FastDFS
ly:
upload:
是定义传入文件校验时要用的。

fdfs:
  so-timeout: 1501
  connect-timeout: 601
  thumb-image: # 缩略图
    width: 60
    height: 60
  tracker-list: # tracker地址
    - 192.168.209.128:22122
#    下面配置上传功能的全局信息
ly:
  upload:
    baseUrl: http://image.leyou.com/
    allowTypes:
      - image/jpeg
      - image/png
      - image/bmp
      - image/jpg

读取yml文件中定义的校验信息

@Data
@ConfigurationProperties(prefix = "ly.upload")
public class UploadProperties {
    private String baseUrl;
    private List<String> allowTypes;
}

下面是 FastDFS的java客户端,用的时候@Autowired 注入就可以了

@Configuration
@Import(FdfsClientConfig.class)
// 解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class FastClientImporter {
}

service:

上传所需要的参数:

  1. 上传文件的流,file.getInputStream()就可以得到

  2. 文件的大小,file.getSize()

  3. 文件的扩展名,也就是类型
    String extensionName = StringUtils.substringAfterLast(file.getOriginalFilename(), “.”);
    比如 a.jpg ,得到的就是 . 后面的jpg。

  4. 对这个文件的描述,没有传null就可以了。

  5. 最后返回的是图片的路径,上传成功后会在页面显示出图片的样子。

@Service
@Slf4j
@EnableConfigurationProperties(UploadProperties.class)
public class UploadService {

    @Autowired
    private FastFileStorageClient storageClient;
    
    @Autowired
    private UploadProperties properties;

    /**
     * 上传图片
     *
     * @param file
     * @return
     */
    public String uploadImage(MultipartFile file) {

        try {
            //校验文件类型
            String type = file.getContentType();
            if (!properties.getAllowTypes().contains(type)) {
                throw new LyException(ExceptionEnum.INVALID_FILE_FORMAT);
            }
            //上传到fastFDS
//            substringAfterLast的意思是截取什么符号后面的数据,这里写的是.后面的
            String extensionName = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
            StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), extensionName, null);
            //校验文件内容,如果不是图片则会返回空
            BufferedImage image = ImageIO.read(file.getInputStream());
            if (image == null) {
                throw new LyException(ExceptionEnum.INVALID_FILE_FORMAT);
            }
            //返回路径
            return properties.getBaseUrl() + storePath.getFullPath();
        } catch (IOException e) {
            log.error("上传图片失败!", e);
            throw new LyException(ExceptionEnum.UPLOAD_IMAGE_EXCEPTION);
        }
    }
}

图片上传不是最后一项,在显示图片后也会记录图片的地址存入到tb_sku表中,当查询商品会再从这个地址取图片。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值