小程序开发

【学习日记】微信小程序仿朋友圈发布商品信息及图片

本文主要是介绍【学习日记】微信小程序仿朋友圈发布商品信息及图片,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本文使用的技术栈:小程序开发、SpringBoot、MyBatis、Redis

今天要写一个商城项目中的发布商品模块,需求跟闲鱼这样的app基本一致,就是基本的上传表单数据和图片。图片模块我想采用类似朋友圈的方式来完成,符合大部分用户的操作逻辑。

微信图片_20180928230850.jpg

现在朋友圈发图片已经可以拖拽改变图片顺序或删除图片了,但是用小程序实现拖拽功能太麻烦了。所以,我将换一种方式来实现图片删除和预览,最后,再写两个后端接口,把商品信息和图片存入数据库。

这里前端用到了Vant Weapp的UI库 https://github.com/youzan/vant-weapp

先来看看前端页面的代码

<view class="page">
  <form bindsubmit='send'>
    <van-cell-group>
        <van-field
          required
          clearable
          left-icon="gift"
          name="goodsName"
          label="商品名称"
          icon="question"
          placeholder="请输入商品名"
          bind:click-icon="onClickIcon"
        />

        <van-field
          type="textarea"
          label="描述"
          left-icon="records"
          name="goodsDesc"
          placeholder="请输入5-50个字"
          autosize
          required
          border="{{ false }}"
        />

    </van-cell-group>


    <view class="image_content">
        <view class='image' wx:for="{{img_url}}">
          <image class="deleteImg" mode="aspectFill"  data-index='{{index}}' src="/img/deleteImg.png" bindtap="deleteImg"></image>
          <image class="moment_img" mode="aspectFill" data-index='{{index}}' src="{{item}}" bindtap="previewImg"></image>
        </view>
        <view class='image' style='display:{{hideAdd?"none":"block"}}'>
          <image bindtap="chooseimage" class="moment_img" src='/img/addImg.png'></image>
        </view>
    </view>
 
   <van-cell-group>
        <van-field
          required
          clearable
          left-icon="gold-coin"
          name="goodsPrice"
          label="单价"
          icon="question"
          placeholder="请输入数字"
          bind:click-icon="onClickIcon"
        />

        <van-field
          value="1"
          label="数量"
          left-icon="exchange"
          name="goodsNum"
          placeholder=""
          required
        />

        <van-field
          left-icon="chat"
          name="goodsPhone"
          label="联系方式"
          required
        />

        <van-field
          left-icon="location"
          value=""
          name="goodsAddress"
          label="交易地点"
          placeholder="例:学瀚楼下"
          required
        />

    </van-cell-group>
 
      <button class="publishBtn" type="primary" form-type='submit'>发布</button>
  
  </form>
</view>

效果如下图:

微信图片_20180929165257.jpg

表单部分代码很简单,所以这里主要分析添加图片的代码逻辑。第一步,找一张添加照片的图标绑定一个wx.chooseImage事件,定义一个全局变量count作为当前选择的图片数量,使用户选择的图片在9张以内;定义一个数组,用于存放当前图片的url,在用户选择完照片后,该数组会更新,并用wx:for渲染至前端页面。

 chooseimage: function () {
    var me = this;
    //动态更新当前用户可以上传的图片数
    var count = 9 - that.data.img_url.length;
    wx.chooseImage({
      count: count, // 默认9 
      sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 
      sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 
      success: function (res) {
        if (res.tempFilePaths.length > 0) {
          //把每次选择的图push进数组
          let img_url = that.data.img_url;
          for (let i = 0; i < res.tempFilePaths.length; i++) {
            img_url.push(res.tempFilePaths[i])
          }
          me.setData({
            img_url: img_url
          })
          
          //图如果满了9张,不显示添加图片图标
          if (that.data.img_url.length >= 8) {
            me.setData({
              hideAdd: 1
            })
          } else {
            me.setData({
              hideAdd: 0
            })
          }
        }
      }
    })
  }

当图片数量达到9张,隐藏添加图片图标

图片.png

第二步,给图片加上预览和删除功能,预览功能使用wx.previewImage绑定图片的索引值即可;删除功能则是在图片右上角加上一个删除图标来绑定删除事件,删除后实时更新图片列表。

图片.png

  //预览图片
  previewImg:function(e){
    var me = this;
    var img_url = me.data.img_url;
    var index = e.target.dataset.index;
    wx.previewImage({
      urls: img_url,
      current : img_url[index],
      success:function(res){
          console.log(res);
      }
    })
  },

  //删除图片
  deleteImg: function (e){
    var me = this;
    var img_url = me.data.img_url;
    var index = e.target.dataset.index;
    img_url.splice(index, 1); 
    me.setData({
      img_url: img_url,
      //若当前图片超过9张,则隐藏添加图标;少于9张则显示添加图标。
      hideAdd: me.data.img_url.length <9 ? false : true
    })
  },

第三步,上传商品信息和图片,我将这个功能分为两部分完成,首先将表单数据先上传,再将图片上传。这里假设用户已经成功使用微信登录小程序,且登录态保存已保存在本地缓存。在表单数据上传成功后,会返回一个商品ID到前端,再调用上传图片方法,将商品ID和每张图片的相对路径保存至数据库。实现代码如下。

//上传商品信息
send:function(e){
    var me = this;
    console.log(e);
    var goodsName = e.detail.value.goodsName;
    var goodsDesc = e.detail.value.goodsDesc;
    var goodsPrice = e.detail.value.goodsPrice;
    var goodsNum = e.detail.value.goodsNum;
    var goodsAddress = e.detail.value.goodsAddress;
    var goodsPhone = e.detail.value.goodsPhone;
    var thirdSession = wx.getStorageSync("thirdsession")
    wx.showLoading({
      title: '发布中--',
    })
    var serverUrl = app.serverUrl;
    wx.request({
      url: serverUrl + '/goods/uploadGoods',
      data: {
        thirdSession: thirdSession,
        goodsName: goodsName,  
        goodsDesc: goodsDesc,
        goodsPrice: goodsPrice,
        goodsNum: goodsNum,
        goodsAddress: goodsAddress,
        goodsPhone: goodsPhone,
      },
      method: "GET",
      success: function (res) {
        wx.hideLoading();
        console.log(res.data.data);
        //商品信息上传成功后,上传商品图片
        me.uploadGoodsImg(res.data.data);
      }
    })
  }

需要注意的是,小程序的wx.uploadFile接口的资源路径是String类的。所以多图上传时,我会递归调用这个接口来完成。

图片.png

 //上传图片
 uploadGoodsImg: function (goodsId){
    var me = this;
    var imgFilePaths = me.data.img_url;
    var count = me.data.count;
    var serverUrl = app.serverUrl;
    wx.showLoading({
      title: '上传图片中--',
    })
    wx.uploadFile({
      url: serverUrl + '/goods/uploadGoodsImg', 
      filePath: imgFilePaths[count],
      name: 'file',
      formData: {
        goodsId: goodsId
      },
      success: function (res) {
          //可统计成功上传图片数
      },
      fail: function (res) {
          //可统计上传失败图片数
      },
      complete: function (res) {
        count++;
        me.setData({
          count: count
        })
        if (count >= imgFilePaths.length) {
          var data = JSON.parse(res.data);
          console.log(data);
          wx.hideLoading();
          if (data.status == 200) {
            wx.hideLoading();
            wx.showToast({
              title: '上传成功!~~',
              icon: 'success'
            });
            me.setData({
              count: 0
            })
          } else if (data.status == 500) {
            wx.showToast({
              title: data.msg,
            });
          }
        } else {
          //图片未上传完,递归调用本方法。
          me.uploadGoodsImg(goodsId);
        }
      }
    })
  }

第四步,后端接口使用IO流工具IOUtils将图片写入到指定的路径下,并将相对路径保存至数据库。这里存放图片路径采用了一个单独的表。具体代码如下:

    //保存商品信息
	@GetMapping("/uploadGoods")
	public IMoocJSONResult uploadFace(String thirdSession,String goodsName,
			String goodsDesc,double goodsPrice,String goodsPhone,
			int goodsNum,String goodsAddress) throws Exception {
		
		if (StringUtils.isBlank(thirdSession)) {
			return IMoocJSONResult.errorMsg("thirdSession is none");
		}

        String value = (String) redis.get("Wxuser-redis-session:"+thirdSession);
        System.out.println(value);
        if (StringUtils.isBlank(value)) {
            return IMoocJSONResult.errorMsg("session timeout");
        }
        //解析json格式的str
        JSONObject json = JSONObject.parseObject(value);
        String openId = json.getString("openid");
		
        String goodsId = sid.nextShort();
		
		Goods goods = new Goods();
		goods.setId(goodsId);
		goods.setSellerId(openId);
		goods.setSellerPhone(goodsPhone);
		goods.setAddress(goodsAddress);
		goods.setGoodsDesc(goodsDesc);
		goods.setLikeCounts(0);
		goods.setGoodsName(goodsName);
		goods.setPrice(goodsPrice);
		goods.setGoodsNum(goodsNum);
		
		goodsService.saveGoods(goods);
		
		return IMoocJSONResult.ok(goodsId);
	
	}

上传图片接口

@PostMapping(value="/uploadGoodsImg" ,headers="content-type=multipart/form-data")
public IMoocJSONResult uploadGoodsImg(String goodsId,@RequestParam("file") MultipartFile[] files) throws Exception {

		//文件保存的命名空间
		String fileSpace="D:/cunjin-xianyu-test";
		//保存到数据库的相对路径
		String uploadPathDB="/"+goodsId+"/img";
		FileOutputStream fileOutputStream=null;
		InputStream inputStream= null;
		try {
			if(files != null && files.length>0) {
				String fileName= files[0].getOriginalFilename();
				if (StringUtils.isNotBlank(fileName)) {
					//文件保存的最终路径
					String finalPath = fileSpace + uploadPathDB + "/" + fileName;
				    //设置数据库保存的路径
					uploadPathDB+=("/"+fileName);
					
					File outFile=new File(finalPath);
					
					if (outFile.getParentFile()!=null || !outFile.getParentFile().isDirectory()) {
						//创建父文件夹
						outFile.getParentFile().mkdirs();
					}
					fileOutputStream = new FileOutputStream(outFile);
					inputStream = files[0].getInputStream();
					IOUtils.copy(inputStream, fileOutputStream);
				}else {
					return IMoocJSONResult.errorMsg("上传出错");
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return IMoocJSONResult.errorMsg("上传出错");
		}finally {
			if(fileOutputStream!=null) {
				fileOutputStream.flush();
				fileOutputStream.close();
			}
		}
		
		GoodsImg goodsImg = new GoodsImg();
		goodsImg.setGoodsId(goodsId);
		goodsImg.setImg(uploadPathDB);
		goodsService.saveGoodsImg(goodsImg);
		
		return IMoocJSONResult.ok("上传成功");

}

好了,代码写完了,现在来进行前后端联调,测试一下。我们先选几张图,输一些数据

图片.png

在本地新建一个文件夹,用于存放图片,路径与代码的命名空间一致。

图片.png

好了,现在我们点击发布,观察数据库和本地文件。

图片.png

图片.png

图片.png

可以看到,我们发布的商品信息和图片相对路径都已经存入数据库了,同时,本地也已经保存了这两张图片。测试成功!

总结

  1. 数据库存放多张图片路径,除了用本文的方法,还可以使用一些特定符号将路径分隔开,存入商品信息表中,这样,即使上传多张图片也只会存入一行数据,不过这种方法也是在网上看过,自己还未实践过。
  2. 在使用wx.uploadFile接口时,要记得将content-type改为multipart/form-data。
  3. 使用IOUtils写文件的拷贝非常方便,无需各种输入流,然后读取line,输出到输出流。
点击查看更多内容
这篇关于【学习日记】微信小程序仿朋友圈发布商品信息及图片的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!