天天看點

SpringBoot實作微信小程式檔案上傳的完整案例

文章目錄

  • ​​一、背景​​
  • ​​二、後端實作​​
  • ​​1、SpringBoot項目API相關結構樹​​
  • ​​2、檔案上傳工具類的實作​​
  • ​​3、小程式CRM上傳檔案接口的實作​​
  • ​​4、小程式CRM上傳檔案接口的檢視​​
  • ​​三、前端實作​​
  • ​​1、搭建上傳頁面​​
  • ​​2、編寫上傳代碼​​
  • ​​3、上傳測試​​

一、背景

最近在做一個CRM微信小程式工具,使用者提出了需要通過小程式上傳圖檔、錄音、視訊的需求。針對此需求,本文将通過搭建SpringBoot上傳檔案的API,前端小程式調用後端API,展現微信小程式檔案上傳到SpringBoot的完整案例。

二、後端實作

1、SpringBoot項目API相關結構樹
SpringBoot實作微信小程式檔案上傳的完整案例
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方法

SpringBoot實作微信小程式檔案上傳的完整案例

檔案上傳工具接口: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​​

SpringBoot實作微信小程式檔案上傳的完整案例

三、前端實作

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>      
SpringBoot實作微信小程式檔案上傳的完整案例
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、上傳測試

上傳一張圖檔:

SpringBoot實作微信小程式檔案上傳的完整案例

服務端檔案存儲:

SpringBoot實作微信小程式檔案上傳的完整案例