SpringBoot实现微信小程序文件上传的完整案例

一、背景

最近在做一个CRM微信小程序工具,用户提出了需要通过小程序上传图片、录音、视频的需求。针对此需求,本文将通过搭建SpringBoot上传文件的API,前端小程序调用后端API,展现微信小程序文件上传到SpringBoot的完整案例。

二、后端实现

1、SpringBoot项目API相关结构树

在这里插入图片描述

2、文件上传工具类的实现

tools工具类包中主要存文件通用的文件上传工具类,该工具类会将文件上传至配置指定的文件夹下,并将文件信息写入upload_file表中。

  • 文件信息实体类:与数据库中表upload_file对应;
  • 文件存储仓库类:通过Spring Data JPA接口实现数据的CRUD;
  • 文件上传工具接口:对外统一封装文件上传方法;
  • 文件上传工具实现类:实现文件上传方法接口。

文件信息实体类:UploadFile.java

/**
 * 文件信息表
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
@Entity
@Getter
@Setter
@Table(name = "upload_file")
public class UploadFile {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @NotNull(groups = Update.class)
    private Long id;

    /**
     * 文件实际名称
     */
    @Column(name = "real_name")
    private String realName;

    /**
     * 文件名
     */
    @NotNull
    @Column(name = "file_name")
    private String fileName;

    /**
     * 文件主名称
     */
    @NotNull
    @Column(name = "primary_name")
    private String primaryName;

    /**
     * 文件扩展名
     */
    @NotNull
    private String extension;

    /**
     * 存放路径
     */
    @NotNull
    private String path;

    /**
     * 文件类型
     */
    private String type;

    /**
     * 文件大小
     */
    private Long size;

    /**
     * 上传人
     */
    private String uploader;

    @JsonIgnore
    @Column(name = "create_time")
    @CreationTimestamp
    private Timestamp createTime;

    public UploadFile(String realName, @NotNull String fileName, @NotNull String primaryName, @NotNull String extension, @NotNull String path, String type, Long size, String uploader) {
        this.realName = realName;
        this.fileName = fileName;
        this.primaryName = primaryName;
        this.extension = extension;
        this.path = path;
        this.type = type;
        this.size = size;
        this.uploader = uploader;
    }

    @Override
    public String toString() {
        return "UploadFile{" +
                "fileName='" + fileName + '\'' +
                ", uploader='" + uploader + '\'' +
                ", createTime=" + createTime +
                '}';
    }
}

文件存储仓库类:UploadFileRepository.java

/**
 * 上传文件DAO接口层
 *
 * @author zhuhuix
 * @date 2020-04-03
 */
public interface UploadFileRepository extends JpaRepository<UploadFile, Long>, JpaSpecificationExecutor<UploadFile> {
//该接口继承JpaRepository及CrudRepository接口,已实现了如findById,save,delete等CRUD方法
}

UploadFileRepository 接口继承JpaRepository及CrudRepository接口,已实现了如findById,save,delete等CRUD方法
在这里插入图片描述
文件上传工具接口:UploadFileTool.java

/**
 * 文件上传接口定义
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
public interface UploadFileTool {

    /**
     * 文件上传
     * @param multipartFile 文件
     * @return 上传信息
     */
   UploadFile upload(String uploader,String realName,MultipartFile multipartFile);
}

文件上传工具实现类:UploadFileToolImpl.java

/**
 * 文件上传实现类
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class UploadFileToolImpl implements UploadFileTool {

    private final UploadFileRepository uploadFileRepository;

    @Value("${uploadFile.path}")
    private String path;

    @Value("${uploadFile.maxSize}")
    private long maxSize;

    public UploadFileToolImpl(UploadFileRepository uploadFileRepository) {
        this.uploadFileRepository = uploadFileRepository;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UploadFile upload(String uploader, String realName, MultipartFile multipartFile) {
        //检查文件大小
        if (multipartFile.getSize() > maxSize * Constant.MB) {
            throw new RuntimeException("超出文件上传大小限制" + maxSize + "MB");
        }
        //获取上传文件的主文件名与扩展名
        String primaryName = FileUtil.mainName(multipartFile.getOriginalFilename());
        String extension = FileUtil.extName(multipartFile.getOriginalFilename());
        //根据文件扩展名得到文件类型
        String type = getFileType(extension);
        //给上传的文件加上时间戳
        LocalDateTime date = LocalDateTime.now();
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMddhhmmssS");
        String nowStr = "-" + date.format(format);
        String fileName = primaryName + nowStr + "." + extension;

        try {
            String filePath = path + type + File.separator + fileName;
            File dest = new File(filePath).getCanonicalFile();
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
            multipartFile.transferTo(dest);
            if (ObjectUtil.isNull(dest)) {
                throw new RuntimeException("上传文件失败");
            }

            UploadFile uploadFile = new UploadFile(realName, fileName, primaryName, extension, dest.getPath(), type, multipartFile.getSize(), uploader);
            return uploadFileRepository.save(uploadFile);

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }

    }

    /**
     * 根据文件扩展名给文件类型
     *
     * @param extension 文件扩展名
     * @return 文件类型
     */
    private static String getFileType(String extension) {
        String document = "txt doc pdf ppt pps xlsx xls docx csv";
        String music = "mp3 wav wma mpa ram ra aac aif m4a";
        String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
        String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
        if (image.contains(extension)) {
            return "image";
        } else if (document.contains(extension)) {
            return "document";
        } else if (music.contains(extension)) {
            return "music";
        } else if (video.contains(extension)) {
            return "video";
        } else {
            return "other";
        }
    }
}

注意,该程序代码中用到了@Value注解获取配置文件中的uploadFile.path及uploadFile.maxsize参数,一般在项目静态配置文件中按如下书写(yml配置文件)。

# 测试环境文件存储路径
uploadFile:
  path: C:\startup\file\
  # 文件大小 /M
  maxSize: 50
3、小程序CRM上传文件接口的实现

wx-miniprogram包定义了小程序CRM webApi的接口,小程序调用webApi实现文件的上传及其他功能。

  • 微信小程序CRM webApi:对外提供小程序上传文件webApi;
  • 微信小程序CRM服务接口:封装小程序上传文件服务接口;
  • 微信小程序CRM服务实现:小程序上传文件服务的实现,该服务实现中会调用tools包中的UploadFile接口进行文件的上传。

微信小程序CRM webApi:WxMiniCrmController.java

/**
 * 微信小程序Crm webApi
 *
 * @author zhuhuix
 * @date 2020-03-30
 */
@Slf4j
@RestController
@RequestMapping("/api/wx-mini")
@Api(tags = "微信小程序Crm接口")
public class WxMiniCrmController {

    private final WxMiniCrm wxMiniCrm;

    public WxMiniCrmController(WxMiniCrm wxMiniCrm) {
        this.wxMiniCrm = wxMiniCrm;
    }

    @ApiOperation(value = "微信小程序端上传文件")
    @PostMapping(value = "/fileUpload")
    public ResponseEntity fileUpload(HttpServletRequest request) {
        MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;

        MultipartFile multipartFile = req.getFile("file");
        String openId = req.getParameter("openId");
        String realName = req.getParameter("realName");
        String json = req.getParameter("json");

        return ResponseEntity.ok(wxMiniCrm.uploadFile(json, openId,realName, multipartFile));

    }
}

微信小程序CRM服务接口:WxMiniCrm.java

/**
 * 微信小程序CRM服务接口定义
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
public interface WxMiniCrm {

    /**
     * 将微信小程序传入的json对象写入数据库,并同时将文件上传至服务端
     *
     * @param json          微信端传入json对象
     * @param openId        上传人
     * @param realName      文件实际名称
     * @param multipartFile 上传文件
     * @return 返回上传信息
     */
    Result<UploadFile> uploadFile(String  json, String openId, String realName,MultipartFile multipartFile);
}

微信小程序CRM服务实现:WxMiniCrmImpl.java

/**
 * 微信小程序CRM实现类
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class WxMiniCrmImpl implements WxMiniCrm {

    private final UploadFileTool uploadFileTool;

    public WxMiniCrmImpl(UploadFileTool uploadFileTool) {
        this.uploadFileTool = uploadFileTool;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<UploadFile> uploadFile(String  json, String openId,String realName, MultipartFile multipartFile) {
        return new Result<UploadFile>().ok(uploadFileTool.upload(openId,realName, multipartFile));
    }
}
4、小程序CRM上传文件接口的查看

访问Swagger2可查看该接口,Swagger2与SpringBoot的集成可参考SpringBoot JWT认证机制项目集成Swagger2
在这里插入图片描述

三、前端实现

1、搭建上传页面

上传页面中用到了 有赞vant-weapp Uploader 文件上传组件

<view style="margin-top: 30rpx;">
	<van-cell-group>
		<van-field
		 value="{{ userName }}"
		 label="名称"
		 placeholder="请输入称呼"
		 right-icon="contact"
		 bind:input="onUserNameInput"
		/>
		<van-field
		 value="{{ phone }}"
		 type="number"
		 label="联系方式"
		 placeholder=""
		 right-icon="phone-o"
		 bind:input="onPhoneInput"
		/>
		<van-field
		 value="{{ company }}"
		 label="单位"
		 placeholder="请输入单位名称"
		 right-icon="cluster-o"
		 bind:input="onCompanyInput"
		/>
	</van-cell-group>
</view>

<van-cell-group title="个人信息">
	<van-uploader style="margin-left: 5rpx; padding: 0 20rpx;"
	 file-list="{{ idCardFront }}"
	 max-count="{{ 3 }}"
	 multiple
	 accept="all"
	 max-size= "52428800"
	 bind:before-read="beforeReadIdCardFront"
	 bind:after-read="afterReadIdCardFront"
	 bind:delete="deleteIdCardFront"
	 bind:click-preview="clickPreviewCardImage"
    />

</van-cell-group>

在这里插入图片描述

2、编写上传代码

该代码中调用wx.uploadFile API接口

 /**上传文件 */
  uploadUserCards: function(cards, realName) {
    let uploadCards = cards;
    let uploadRealName = realName;
    uploadCards.forEach(element => {
      console.log("element", element);
      if (typeof element.openId == "undefined") {       
        wx.uploadFile({
          url: api.wxFileUploadUrl,
          filePath: element.path,
          name: "file",
          header: {
            "Authorization": wx.getStorageSync("loginFlag"),
            "Content-Type": "multipart/form-data"
          },
          formData: {
            openId: app.globalData.userInfo.openId,
            realName:realName,
            json: JSON.stringify({"fileName":realName})
          },
          success: result => {
            console.log("success:",result);
            if (result.statusCode == "200") {
              let data = JSON.parse(result.data);
              console.log("data", data);
              if (data.success == true) {
                let module = data.module;
                console.log("module", module);
                let card = {
                  openId: app.globalData.userInfo.openId,
                  cardKey: app.globalData.userInfo.openId,
                  url:
                    api.baseUrl + "file/" + module.type + "/" + module.fileName,
                  name: uploadPictureName,
                  isImage: module.type=="image"? true:false
                };
              } else {
                app.showInfo("异常错误" + data.errMsg + ",请重新进入");
              }
            } else {
              app.showInfo("登录超时,返回上一页,请重新进入");
            }
          },
          fail: result => {
            console.log("fail",result);
          }
        });
      }
    });
  },
3、上传测试

上传一张图片:
在这里插入图片描述
服务端文件存储:
在这里插入图片描述
浏览器访问:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章