微信小程序____上傳圖片(附后端代碼)

引言

最近公司需要做個沖印類型的小程序,一陣徘徊后,才決定快速集成一個微型產品來。

正題

幾乎每個程序都需要用到圖片。
在小程序中我們可以通過image組件顯示圖片。

當然小程序也是可以上傳圖片的,參照微信小程序官方文檔

step_1 選擇圖片

  • 通過wx.chooseImage(OBJECT)實現(xiàn)

官方示例代碼:

wx.chooseImage({ 
  count: 1, // 默認9 
  sizeType: ['original', 'compressed'], // 可以指定是原圖還是壓縮圖,默認二者都有
  sourceType: ['album', 'camera'], // 可以指定來源是相冊還是相機,默認二者都有
  success: function (res) { 
  // 返回選定照片的本地文件路徑列表,tempFilePath可以作為img標簽的src屬性顯示圖片
  var tempFilePaths = res.tempFilePaths } 
  })

圖片最多只可以選擇9張, 也可以通過拍攝照片實現(xiàn),當選擇完圖片之后會獲取到圖片路徑, 這個路徑在本次啟動期間有效。
如果需要保存就需要用wx.saveFile(OBJECT)

step_2 上傳圖片

  • 通過wx.uploadFile(OBJECT) 可以將本地資源文件上傳到服務器。

原理就是客戶端發(fā)起一個 HTTPS POST 請求,其中 content-typemultipart/form-data

官方示例代碼

wx.chooseImage({
  success: function(res) {
    var tempFilePaths = res.tempFilePaths
    wx.uploadFile({
      url: 'http://example.weixin.qq.com/upload', //僅為示例,非真實的接口地址
      filePath: tempFilePaths[0],
      name: 'file',
      formData:{
        'user': 'test'
      },
      success: function(res){
        var data = res.data
        //do something
      }
    })
  }
})

示例代碼

看完了文檔, 寫一個上傳圖片就沒有那么麻煩了,下面是真實場景的代碼

import constant from '../../common/constant';
Page({
  data: {
    src: "../../image/photo.png",  //綁定image組件的src
     //略...
  },
  onLoad: function (options) {
      //略... 
  },
  uploadPhoto() {
    var that = this; 
    wx.chooseImage({
      count: 1, // 默認9
      sizeType: ['compressed'], // 可以指定是原圖還是壓縮圖,默認二者都有
      sourceType: ['album', 'camera'], // 可以指定來源是相冊還是相機,默認二者都有
      success: function (res) {
        // 返回選定照片的本地文件路徑列表,tempFilePath可以作為img標簽的src屬性顯示圖片
        var tempFilePaths = res.tempFilePaths;
        upload(that, tempFilePaths);
      }
    })
  }
})

function upload(page, path) {
  wx.showToast({
    icon: "loading",
    title: "正在上傳"
  }),
  wx.uploadFile({
    url: constant.SERVER_URL + "/FileUploadServlet",
    filePath: path[0], 
    name: 'file',
    header: { "Content-Type": "multipart/form-data" },
    formData: {
      //和服務器約定的token, 一般也可以放在header中
      'session_token': wx.getStorageSync('session_token')
    },
    success: function (res) {
      console.log(res);
      if (res.statusCode != 200) { 
        wx.showModal({
          title: '提示',
          content: '上傳失敗',
          showCancel: false
        })
        return;
      }
      var data = res.data
      page.setData({  //上傳成功修改顯示頭像
        src: path[0]
      })
    },
    fail: function (e) {
      console.log(e);
      wx.showModal({
        title: '提示',
        content: '上傳失敗',
        showCancel: false
      })
    },
    complete: function () {
      wx.hideToast();  //隱藏Toast
    }
  })
}
后端代碼

后端是用java寫的,一開始的時候,后端開始用了一些框架接收上傳的圖片,出現(xiàn)了各種問題,后來使用了純粹的Servlet就沒有了問題, 把代碼貼出來省的以后麻煩了。

注意: 代碼使用了公司內部的框架,建議修改后再使用

public class FileUploadServlet extends HttpServlet {
    
    private static final long serialVersionUID = 1L;
    private static Logger logger = LoggerFactory.getLogger(FileUploadServlet.class);
    
    public FileUploadServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        JsonMessage<Object> message = new JsonMessage<Object>();
        EOSResponse eosResponse = null;
        String sessionToken = null;
        FileItem file = null;
        InputStream in = null;
        ByteArrayOutputStream swapStream1 = null;
        try {
            request.setCharacterEncoding("UTF-8"); 
            
            //1、創(chuàng)建一個DiskFileItemFactory工廠  
            DiskFileItemFactory factory = new DiskFileItemFactory();  
            //2、創(chuàng)建一個文件上傳解析器  
            ServletFileUpload upload = new ServletFileUpload(factory);
            
            //解決上傳文件名的中文亂碼  
            upload.setHeaderEncoding("UTF-8");   
            // 1. 得到 FileItem 的集合 items  
            List<FileItem> items = upload.parseRequest(request);
            logger.info("items:{}", items.size());
            // 2. 遍歷 items:  
            for (FileItem item : items) {  
                String name = item.getFieldName();  
                logger.info("fieldName:{}", name);
                // 若是一個一般的表單域, 打印信息  
                if (item.isFormField()) {  
                    String value = item.getString("utf-8");  
                    if("session_token".equals(name)){
                        sessionToken = value;
                    }
                }else {
                    if("file".equals(name)){
                        file = item;
                    }
                }  
            }
            //session校驗
            if(StringUtils.isEmpty(sessionToken)){
                message.setStatus(StatusCodeConstant.SESSION_TOKEN_TIME_OUT);
                message.setErrorMsg(StatusCodeConstant.SESSION_TOKEN_TIME_OUT_MSG);
            }
            String userId = RedisUtils.hget(sessionToken,"userId");
            logger.info("userId:{}", userId);
            if(StringUtils.isEmpty(userId)){
                message.setStatus(StatusCodeConstant.SESSION_TOKEN_TIME_OUT);
                message.setErrorMsg(StatusCodeConstant.SESSION_TOKEN_TIME_OUT_MSG);
            }
            //上傳文件
            if(file == null){
            }else{
                swapStream1 = new ByteArrayOutputStream();
                
                in = file.getInputStream();
                byte[] buff = new byte[1024];
                int rc = 0;
                while ((rc = in.read(buff)) > 0) {
                    swapStream1.write(buff, 0, rc);
                }
                
                Usr usr = new Usr();
                usr.setObjectId(Integer.parseInt(userId));
                
                final byte[] bytes = swapStream1.toByteArray();
                
                eosResponse= ServerProxy.getSharedInstance().saveHeadPortrait(usr, new RequestOperation() {
                    
                    @Override
                    public void addValueToRequest(EOSRequest request) {
                        request.addMedia("head_icon_media", new EOSMediaData(EOSMediaData.MEDIA_TYPE_IMAGE_JPEG, bytes));
                    }
                });
                
                // 請求成功的場合
                if (eosResponse.getCode() == 0) {
                    message.setStatus(ConstantUnit.SUCCESS);
                } else {
                    message.setStatus(String.valueOf(eosResponse.getCode()));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            try {
                if(swapStream1 != null){
                    swapStream1.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(in != null){
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        PrintWriter out = response.getWriter();  
        out.write(JSONObject.toJSONString(message));  
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

小程序前端效果____仿朋友圈的照片上傳。

很粗糙、很簡陋,請勿怪。

先上圖:

首先說明一下我的前端基本訴求:

  • 一行明確指定圖片顯示個數(shù)
  • 可從照片圖庫一次多選若干張照片并顯示在前端
  • 照片與照片之間有明顯的間隔
  • 達到一定數(shù)量照片時將添加按鈕隱藏
  • 添加按鈕加上一些樣式

index.wxml

<view class='uploadContainer'>
  <view wx:for="{{image}} wx:key="*this"">
    <image src='{{image[index]}}' bindload='imageLoad' style='width:{{pic_width}}px;height:{{pic_height}}px;margin:{{margin_length}}px' />
    <button bindtap='deleteImg' data-num='{{index}}' class='deleteBtn' style='width:{{pic_width}}px;margin:{{margin_length}}px'>刪除</button>
  </view>
  <image src='../../icons/add.png' bindtap='uploadImg' class='addimg' style='display:{{img_button}};width:{{pic_width-2}}px;height:{{pic_height-2}}px ;margin:{{margin_length}}px' />
</view>

index.wxss

.uploadContainer {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  flex-wrap: wrap;
}
.addimg {
  border-style: inset;
  border-width: 1px;
  border-color: #ddd;
}

index.js

//index.js
//獲取應用實例
var app = getApp()
var px2rpx = 2, windowWidth = 375;
Page({
  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    pic_width: 300,    //初始化值
    pic_height: 300,  //初始化值

    img_button: 'inline-block',
    image: [],
    msg: '',
    margin_length: 3,//顯示圖片的外邊距margin值(單位:px像素)
  },

  //事件處理函數(shù)
  onLoad: function () {
    console.log('onLoad');
    wx.getSystemInfo({
      success: function (res) {
        windowWidth = res.windowWidth;
        px2rpx = 750 / windowWidth;
      }
    })

    this.setData({
      pic_width: (windowWidth - 8 * this.data.margin_length) / 4,
      pic_height: (windowWidth - 8 * this.data.margin_length) / 4
    })
  },

  onPullDownRefresh: function () {
    wx.stopPullDownRefresh()
  },

  onShareAppMessage: function () {
    return {
      title: 'xx公司',
      path: 'pages/index/index'
    }
  },

  uploadImg: function () {
    var that = this;
    var image = this.data.image;
//設定最終一起上傳照片的最大數(shù)量
    if (this.data.image.length < 101) {
      wx.chooseImage({
        count: 9, // 默認9        
        sizeType: ['original'], // 可以指定是原圖還是壓縮圖,默認二者都有        
        sourceType: ['album', 'camera'], // 可以指定來源是相冊還是相機,默認二者都有        
        success: function (res) {
          wx.uploadFile({
            url: app.appUrl.url + 'upload',//這個方法就是后臺處理上傳的方法            
            filePath: res.tempFilePaths[0], //獲取到上傳的圖片            
            name: 'file',
            success: function (info) {
              console.log(info);//info.data就是上傳成功的圖片名稱 您可以在wxml里面搞一個隱藏域存儲起來,在上面Submit提交里拼裝一塊提交出去  
            }
          })
        },
        complete: function (res) {
          // 返回選定照片的本地文件路徑列表,tempFilePath可以作為img標簽的src屬性顯示圖片
          console.log(res.tempFilePaths);
          //判空處理,不能使用res.tempFilePaths.length方法,會報空指針
          //解決了取消選擇照片時會將空照片上傳的問題
          if(res.tempFilePaths!=null){
          //語法:concat的用法,concat之后返回的是一個新的對象,因此要賦值給image
          image=image.concat(res.tempFilePaths);
          that.setData({ image: image })
          //當有100張照片上傳時,將上傳圖片的按鈕隱藏掉
          if (that.data.image.length == 100) {
            that.setData({
              img_button: 'none',
            })
          }
          }
        }
      })
    }
  },
  deleteImg: function (e) {
    var image = this.data.image;
    image.splice(e.currentTarget.dataset.num, 1);
    this.setData({
      image: image,
      img_button: 'inline-block',
    })
  },
})

小程序前端效果____自定義需求。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 幾乎每個程序都需要用到圖片。在小程序中我們可以通過image組件顯示圖片。 當然小程序也是可以上傳圖片的,微信小程...
    于連林520wcf閱讀 83,341評論 10 55
  • 圖片上傳相關文章 微信小程序多張圖片上傳功能 微信小程序開發(fā)(二)圖片上傳 微信小程序上傳一或多張圖片 微信小程序...
    極樂叔閱讀 1,923評論 0 11
  • 第一章 什么是微信小程序 1. 小程序介紹 微信小程序是一種全新的連接用戶與服務的方式,它可以在微信內被便捷地獲取...
    呆毛和二貨閱讀 867評論 0 1
  • 2016年,我28,未婚 無房 無車 無存款 這些不重要,重要的是,我真不想“死” 1997年 10歲 那時愛上繪...
    康汀閱讀 891評論 0 1
  • 尼爾斯花栗鼠像一個調皮好動的男孩子,他不僅堅信人類的存在,還好奇關于人類的一切,比如電燈,書。最主要的就是他手上的...
    野地百合_35b6閱讀 682評論 1 4