2020.11.30 小程序中文件上传

本功能模块中主要实现了前端图片文件以及相关信息的获取以及上传到后台服务器,并存储在数据库表中。
前端:微信小程序
后台:springboot+mybatis
主要实现逻辑:
1.前端获取所需要的信息
2.上传到后台服务器
3.后台接受数据,根据得到的skey查找对应用户的openid
4.根据日期生成存储文件的路径,并存储文件
5.将openid,文件路径相关,及其他获取的信息存储在数据库表中

本文主要记录,实现过程中使用的函数,后台搭建方法,出现的错误以及解决

前端实现:

需要获取的信息有1.定位信息,2.图片文件信息 3.其他输入框以及文本框中的信息
定位信息的获取:
使用的是腾讯位置服务的API在这里插入图片描述

var QQMapWX = require('../../libs/qqmap-wx-jssdk.js');
var qqmapsdk;
Page({
 
    onLoad: function () {
        // 实例化API核心类
        qqmapsdk = new QQMapWX({
            key: '申请的key'
        });
    },
    onShow: function () {
        // 调用接口
        qqmapsdk.search({//使用该方法调用服务接口,获取用户的当前定位
            keyword: '酒店',
            success: function (res) {
                console.log(res);//在返回的res中包含有当前的经度纬度,速度等相关信息
            },
            fail: function (res) {
                console.log(res);
            },
        complete: function (res) {
            console.log(res);
        }
    });
})

在获取的当前定位之后还需要将经纬度转化为街道名称方便描述,这时就用到了地址逆解析服务,将地址转化为位置描述。reverseGeocoder(options:Object)在腾讯位置服务的官方文档中还有很多其他的关于位置的方法。
至此,就可获取需要的位置相关的信息了。

图片文件信息的获取
需要在页面上有一个获取图片的框,点击后可以在获取本机的图片文件,选中之后可以在页面显示,选择错误之后可以删除,还要控制选择的数量。
wxml代码

<view class="menu-list-item">
		<view class="ui_uploader_title">
			<text>上传图片:</text>
		</view>
		<view class='ui_uploader_cell'>
			<!-- 根据已选择的图片临时路径数组展示图片-->

			<view class='ui_uploader_item' wx:for="{{uploaderList}}" wx:key="{{index}}">
				<!-- 删除-->
				<icon class='ui_uploader_item_icon' bindtap='clearImg' data-index="{{index}}" type="clear" size="20" color="red" />
				<!-- 图片-->
				<image bindtap='showImg' data-index="{{index}}" src='{{item}}'></image>
			</view>
			<!-- 上传按钮+框 -->
			<view class='ui_uploader' bindtap='upload' wx:if="{{showUpload}}"></view>

		</view>
	</view>

使用了wx:for循环展示图片框
js代码

  /**
     * 
     * 图片上传相关方法
     */
    // 点击叉号图片删除图片
    clearImg: function (e) {
        var nowList = []; //新数据
        var uploaderList = this.data.uploaderList; //原数据

        for (let i = 0; i < uploaderList.length; i++) {
            if (i == e.currentTarget.dataset.index) {
                continue;
            } else {
                nowList.push(uploaderList[i])
            }
        }
        this.setData({
            uploaderNum: this.data.uploaderNum - 1,
            uploaderList: nowList,
            showUpload: true
        })
    },
    //将获取的图片展示
    showImg: function (e) {
        var that = this;
        wx.previewImage({//微信中图片展示的方法
            urls: that.data.uploaderList,
            current: that.data.uploaderList[e.currentTarget.dataset.index]
        })
    },
    //获取图片本地地址列表uploaderList和数目uploaderNum
    upload: function (e) {

        var that = this;
        wx.chooseImage({
            count: 3 - that.data.uploaderNum, // 默认3
            sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
            sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
            success: function (res) {
                console.log(res)
                // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
                let tempFilePaths = res.tempFilePaths;
                let uploaderList = that.data.uploaderList.concat(tempFilePaths);
                // console.log(uploaderList);
                // 将获取的几个图片的本地路径存在uploaderList中

                if (uploaderList.length == 3) {
                    that.setData({
                        showUpload: false
                    })
                }
                that.setData({
                    uploaderList: uploaderList,
                    uploaderNum: uploaderList.length,
                })
            }
        })
    },

其他相关信息的获取
其他信息包括车位数目,是否付费,描述信息。
基本都是绑定输入方法bindinput,将获取的信息 that.setData临时存储一下。
另外还有一个比较重要的信息是skey。在登录之后会将成功返回的skey存在app.globalData

 var app = getApp();
 var skey = getApp().globalData.skey;

至此前端页面上要获取的信息基本已经获取完了

前端信息上传

微信小程序中对于普通的信息上传用wx.request,文件信息的上传使用wx.uploadFile.
其中有几个重要的字段

 filePath: uploaderList[count],//文件路径,(一定得是单个文件,不能传递一个数组)
     name: 'picfile',//文件名称,一定要和后台对应
      url: app.globalData.domain + '/publish',
 formData: {}//其他要上传的字段

后端实现

后端需要接受从前端获取的文件,根据日期生成文件路径,再将相关信息存在数据库表中。
文件目录
在这里插入图片描述
1.在wxPublishController中接收获取的信息,根据日期生成文件目录,并将信息存储在数据库

package com.turbolee.parkingtestback.controller;
import com.turbolee.parkingtestback.common.JSONResult;
import com.turbolee.parkingtestback.entity.wxUser;
import com.turbolee.parkingtestback.entity.wxUserPublish;
import com.turbolee.parkingtestback.service.wxPublishService;
import com.turbolee.parkingtestback.service.wxUserService;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * 控制前端车位上传
 */
@RestController
public class wxPublishController {
    @Autowired
private wxPublishService wxpublishservice;
    @Autowired
    wxUserService userService;
//接收前端传来的信息数据
    @PostMapping("/publish")
    public JSONResult publish(@RequestParam(value = "picfile",required = false) MultipartFile picfile,
                              @RequestParam(value = "skey",required = false)String skey,
                              @RequestParam(value = "loc_latitude",required = false)String loc_latitude,
                              @RequestParam(value = "loc_longitude",required = false)String loc_longitude,
                              @RequestParam(value = "loc_streetName",required = false)String loc_streetName,
                              @RequestParam(value = "payOrNot",required = false) String payOrNot,
                              @RequestParam(value = "descriptionNote",required = false)String descriptionNote,
                              @RequestParam(value = "spaceNumber" , required = false)String spaceNumber)throws IOException{
        /**
         * 1.根据得到的skey查到对应用户的openid
         * 2.生成publishID(可以自动生成)
         * 3.将获取的图片存储到服务器,获取存储路径
         * 4.将上传的信息,图片存储路径等信息存储到数据库中
         */
        /**
         * 1.获取到对应是skey的openid
         * 查找openid不应该是publishservice 而是userservicev
         */
       wxUser wxuser =userService.getOpenidBySkey(skey);
       String openid  = wxuser.getOpen_id();
        /**
         * 3 处理图片文件的上传,存储到文件夹中,获取存储的路径
         */
        // 获取文件的原始名称
        String fileName = picfile.getOriginalFilename();
        // 获取文件的后缀
        String extension = FilenameUtils.getExtension(picfile.getOriginalFilename());
        // 获取文件的大小
        long size = picfile.getSize();
        // 获取文件的类型
        String type = picfile.getContentType();
        // 根据日期动态的生成目录
        String localContainer = "fileContainer";
        String uploadPath = ResourceUtils.getURL("classpath").getPath() + localContainer;
        String dateFormat = new SimpleDateFormat("yyyy-MM-dd-mm-ss").format(new Date());
        File dateDirPath = new File(uploadPath + File.separator + dateFormat);
        if (!dateDirPath.exists()) {
            dateDirPath.mkdirs();
        }
        System.out.println(dateDirPath);
        // 处理文件上传
        picfile.transferTo(new File(dateDirPath, fileName));
        /**
         * 4.将所有的信息存到对应数据库表中
         */
        wxUserPublish userPulish = new wxUserPublish();
        userPulish.setUser_open_id(openid);
        userPulish.setPic_Name(fileName);
        userPulish.setPic_path(Paths.get(localContainer, dateFormat, fileName).toString());
        userPulish.setPic_extension('.'+extension);
        userPulish.setPic_size(size);
        userPulish.setLoc_latitude(loc_latitude);
        userPulish.setLoc_longitude(loc_longitude);
        userPulish.setLoc_streetName(loc_streetName);
        userPulish.setDescriptionNote(descriptionNote);
        userPulish.setPayOrNot(payOrNot);
        //将String强转为int
        userPulish.setSpaceNumber(Integer.parseInt(spaceNumber));
       wxpublishservice.saveMsg(userPulish);
        return JSONResult.ok();
    }
}

2.为了将文件数据存储在数据库表中,需要创建和数据库对应的实体类

package com.turbolee.parkingtestback.entity;
//上传停车位的信息数据
public class wxUserPublish {
    private int publishID;
    private String user_open_id;
    private String pic_Name;
    private String pic_extension;
    private double pic_size;
    private String pic_path;
    private String loc_latitude;
    private String loc_longitude;
    private String loc_streetName;
    private String payOrNot;
    private String descriptionNote;
    private int spaceNumber;

    public int getPublishID() {
        return publishID;
    }

    public void setPublishID(int publishID) {
        this.publishID = publishID;
    }

    public String getUser_open_id() {
        return user_open_id;
    }

    public void setUser_open_id(String user_open_id) {
        this.user_open_id = user_open_id;
    }

    public String getPic_Name() {
        return pic_Name;
    }

    public void setPic_Name(String pic_Name) {
        this.pic_Name = pic_Name;
    }

    public String getPic_extension() {
        return pic_extension;
    }

    public void setPic_extension(String pic_extension) {
        this.pic_extension = pic_extension;
    }

    public double getPic_size() {
        return pic_size;
    }

    public void setPic_size(double pic_size) {
        this.pic_size = pic_size;
    }

    public String getPic_path() {
        return pic_path;
    }

    public void setPic_path(String pic_path) {
        this.pic_path = pic_path;
    }

    public String getLoc_latitude() {
        return loc_latitude;
    }

    public void setLoc_latitude(String loc_latitude) {
        this.loc_latitude = loc_latitude;
    }

    public String getLoc_longitude() {
        return loc_longitude;
    }

    public void setLoc_longitude(String loc_longitude) {
        this.loc_longitude = loc_longitude;
    }

    public String getLoc_streetName() {
        return loc_streetName;
    }

    public void setLoc_streetName(String loc_streetName) {
        this.loc_streetName = loc_streetName;
    }

    public String getPayOrNot() {
        return payOrNot;
    }

    public void setPayOrNot(String payOrNot) {
        this.payOrNot = payOrNot;
    }

    public String getDescriptionNote() {
        return descriptionNote;
    }

    public void setDescriptionNote(String descriptionNote) {
        this.descriptionNote = descriptionNote;
    }

    public int getSpaceNumber() {
        return spaceNumber;
    }

    public void setSpaceNumber(int spaceNumber) {
        this.spaceNumber = spaceNumber;
    }

    @Override
    public String toString() {
        return "wxUserPublish{" +
                "publishID=" + publishID +
                ", user_open_id='" + user_open_id + '\'' +
                ", pic_Name='" + pic_Name + '\'' +
                ", pic_extension='" + pic_extension + '\'' +
                ", pic_size=" + pic_size +
                ", pic_path='" + pic_path + '\'' +
                ", loc_latitude='" + loc_latitude + '\'' +
                ", loc_longitude='" + loc_longitude + '\'' +
                ", loc_streetName='" + loc_streetName + '\'' +
                ", payOrNot='" + payOrNot + '\'' +
                ", descriptionNote='" + descriptionNote + '\'' +
                ", spaceNumber=" + spaceNumber +
                '}';
    }
}

3service层的service类

package com.turbolee.parkingtestback.service;

import com.turbolee.parkingtestback.dao.wxPublishMapper;
import com.turbolee.parkingtestback.entity.wxUserPublish;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class wxPublishService {

    @Autowired
    wxPublishMapper wxpublishmapper;
//    根据用户skey查询openid
   public void saveMsg(wxUserPublish userpublish){
        wxpublishmapper.saveMsg(userpublish);
   }

}

4.dao中的mapper接口

package com.turbolee.parkingtestback.dao;

import com.turbolee.parkingtestback.entity.wxUserPublish;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository
@Mapper
public interface wxPublishMapper {

    public void saveMsg(wxUserPublish userpublish);


}

5.xml中的mapper实现,需要绑定namespace,绑定返回数据类型resultmap,查询方法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.turbolee.parkingtestback.dao.wxPublishMapper">

    <resultMap id="onlyOne" type="com.turbolee.parkingtestback.entity.wxUserPublish">
        <result column="publishID" jdbcType="INTEGER" property="publishID" />
        <result column="user_open_id" jdbcType="VARCHAR" property="user_open_id" />
        <result column="pic_extension" jdbcType="VARCHAR" property="pic_extension" />
        <result column="pic_size" jdbcType="DOUBLE" property="pic_size" />
        <result column="pic_Name" jdbcType="VARCHAR" property="pic_Name" />
        <result column="pic_path" jdbcType="VARCHAR" property="pic_path" />
        <result column="loc_latitude" jdbcType="VARCHAR" property="loc_latitude" />
        <result column="loc_longitude" jdbcType="VARCHAR" property="loc_longitude" />
        <result column="loc_streetName" jdbcType="VARCHAR" property="loc_streetName" />
        <result column="loc_longitude" jdbcType="VARCHAR" property="loc_longitude" />
        <result column="payOrNot" jdbcType="VARCHAR" property="payOrNot" />
        <result column="descriptionNote" jdbcType="VARCHAR" property="descriptionNote" />
        <result column="spaceNumber" jdbcType="INTEGER" property="spaceNumber" />
    </resultMap>


    <insert id="saveMsg" parameterType="com.turbolee.parkingtestback.entity.wxUserPublish" >
        insert into
        wx_publishpic(user_open_id,pic_Name,pic_extension,pic_size,pic_path,loc_latitude,loc_longitude,loc_streetName,payOrNot,descriptionNote,spaceNumber)
        values
        (#{user_open_id},#{pic_Name},#{pic_extension},#{pic_size},#{pic_path},#{loc_latitude},#{loc_longitude},#{loc_streetName},#{payOrNot},#{descriptionNote},#{spaceNumber})
    </insert>

</mapper>

实现过程中出现的错误

1.一个实体类对应一个数据库表,对应一个mapper.xml,要对某一个表进行处理时,就是用该表对应的mapper,而不是用一个mapper处理所有需要的数据库表。在controller中实例化不同的service。
2.关于@autowired的使用,需要实例化一个对象就要在前面加一个注解,而不是一个注解可以管很多个对象。
3.程序一直绑定不上mapper,但是通过检查,namespace,方法id,数据字段都写的没问题,后来检查发现是这个文件没有加后缀.xml

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值