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

引言

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

正題

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

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

step_1 選擇圖片

  • 通過wx.chooseImage(OBJECT)實現

官方示例代碼:

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

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

step_2 上傳圖片

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

原理就是客戶端發起一個 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寫的,一開始的時候,后端開始用了一些框架接收上傳的圖片,出現了各種問題,后來使用了純粹的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、創建一個DiskFileItemFactory工廠  
            DiskFileItemFactory factory = new DiskFileItemFactory();  
            //2、創建一個文件上傳解析器  
            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);
    }

}

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

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

先上圖:

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

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

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({
  /**
   * 頁面的初始數據
   */
  data: {
    pic_width: 300,    //初始化值
    pic_height: 300,  //初始化值

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

  //事件處理函數
  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;
//設定最終一起上傳照片的最大數量
    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',
    })
  },
})

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容

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