安卓Base64批量上傳至伺服器
Step1:整體過程
/**
* 由於請求框架開始就是Xutils compile ‘org.xutils:xutils:3.3.36’ 不做更改
* 1.第三方的圖片選擇器(支援選擇多張圖片、預覽、刪除等)
* 2.onActivityResult 返回選擇圖片的陣列
* 3.注意:介面有2個 A介面:專門用於接受圖片base64碼 B介面用來上傳 標題、內容和拼接的url連結
* 4.
* ①:將選取的圖片路徑的轉化為base64字串 encode()方法
* ②:選取多張時採用計數疊加一張張的上傳 每上傳一張將地址進行拼接 StringBuffer()方法
* ③:當上傳圖片完成時A介面結束,在呼叫B介面 傳入對應的引數即可,圖片是多張之後的url連結,要去除第一個,號否則後臺解析失敗 substring()方法
*/
上圖中一共上傳了9張圖片,藍色部分就是一至9張的疊加連結,一共花了9秒 當然這些圖片都是很小的,如果是高清圖 記著一定要壓縮 否則會非常慢,因為流程非常多,容易卡死
Step3:進入主題
build.gradle 引入這些
//recyclerview 展示圖片的
compile 'com.android.support:recyclerview-v7:25.3.1'
//請求網路框架xutils
compile 'org.xutils:xutils:3.3.36'
//載入圖片的glide
compile 'com.github.bumptech.glide:glide:3.7.0'
//相簿選擇器
compile 'me.iwf.photopicker:PhotoPicker:[email protected]'
//壓縮圖片的
compile 'com.zxy.android:tiny:0.0.6'
//刪除圖片顯示的snackbar
compile 'com.android.support:design:26.0.0-alpha1
Step4:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.helloworld.base64demo"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".AppContext"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- photopicker圖片選取介面 -->
<activity
android:name="me.iwf.photopicker.PhotoPickerActivity"
android:theme="@style/Theme.AppCompat.NoActionBar" />
<!-- photopicker選取圖片預覽刪除介面 -->
<activity
android:name="me.iwf.photopicker.PhotoPagerActivity"
android:theme="@style/Theme.AppCompat.NoActionBar" />
</application>
</manifest>
Step5:4個java類
1.AppContext
2.MainActivity
3.PhotoAdapter
4.RecyclerItemClickListener
1.
package com.helloworld.base64demo;
import android.app.Application;
import com.zxy.tiny.Tiny;
import org.xutils.x;
public class AppContext extends Application {
public static AppContext mInstace;
@Override
public void onCreate() {
super.onCreate();
/**
* 初始化第三方庫
*/
x.Ext.init(this);
mInstace = this;
/**
* 壓縮的
*/
Tiny.getInstance().getApplication();
}
}
2.
package com.helloworld.base64demo;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.zxy.tiny.Tiny;
import com.zxy.tiny.callback.BitmapCallback;
import org.json.JSONException;
import org.json.JSONObject;
import org.xutils.common.Callback;
import org.xutils.http.RequestParams;
import org.xutils.x;
import java.io.ByteArrayOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import me.iwf.photopicker.PhotoPicker;
import me.iwf.photopicker.PhotoPreview;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private PhotoAdapter photoAdapter;
private ArrayList<String> selectedPhotos = new ArrayList<>();
//原生進度框
private ProgressDialog progressdialog;
private static final String TAG = "ReleaseActivity";
/**
* 圖片路徑
*/
private List<String> photos;
//釋出標題、內容介面 (這裡的連結換上自己伺服器上的)
private static final String URL = "http://110.110.110.10:8080/api/information/publicInformation";
//上傳圖片的介面 專門接受base64嗎
private static final String URLIMAGE = "http://110.110.110.10:8080/api/information/uploadImage";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) this.findViewById(R.id.recyclerView);
progressdialog = new ProgressDialog(this);
progressdialog.setMessage("正在上傳,請稍後...");
//釋出按鈕事件
TextView release_submit = (TextView) this.findViewById(R.id.release_submit);
release_submit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//點選後顯示彈框
progressdialog.show();
UploadImageBase64();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss ");
Date curDate = new Date(System.currentTimeMillis());//獲取當前時間
String str = formatter.format(curDate);
Log.e(TAG, "UploadImageBase6開始時間: " + str);
}
});
initview();
}
private void initview() {
photoAdapter = new PhotoAdapter(this, selectedPhotos);
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, OrientationHelper.VERTICAL));
recyclerView.setAdapter(photoAdapter);
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, new RecyclerItemClickListener
.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
if (photoAdapter.getItemViewType(position) == PhotoAdapter.TYPE_ADD) {
PhotoPicker.builder()
.setPhotoCount(9) //可選擇的圖片數
.setShowCamera(true)//是否開啟相機
.setPreviewEnabled(false)
.setSelected(selectedPhotos)//選擇過的圖片出來在進入,預設打上勾
.start(MainActivity.this);
} else {
PhotoPreview.builder()
.setPhotos(selectedPhotos)
.setCurrentItem(position)
.start(MainActivity.this);
}
}
}));
}
/**
* 選擇了圖片
*/
private String str;
private void UploadImageBase64() {
//當number大於或等於圖片組大小時結束,並return
if (number >= photos.size()) {
//代表圖片上傳完畢,開始釋出
if (photos.size() > 1) {
//圖片大於1張時去除第一個,
str = String.valueOf(sb).substring(1, sb.length());
} else {
str = String.valueOf(sb);
}
//請求的連結、誰釋出的(一般為uid)、釋出的標題、釋出的內容、最後拼接的圖片連結
testUploadFile(URL, "1", "123", "456", str);
//列印 最後拼接的圖片連結
Log.e(TAG, "UploadImageBase64圖片: " + str);
return;
}
//隨便找的壓縮方法 可以自己寫在工具類裡 不建議用第三方的
Tiny.BitmapCompressOptions options = new Tiny.BitmapCompressOptions();
Tiny.getInstance().source(photos.get(number)).asBitmap().withOptions(options).compress(new BitmapCallback() {
@Override
public void callback(boolean isSuccess, Bitmap bitmap) {
//A介面 請求專門上傳圖片的連結、每次轉換時的base64字串、
// 這裡的2只是區別是頭像上傳還是朋友圈上傳 可去除該引數
UploadFile(URLIMAGE, "1", encode(photos.get(number)), "2");
//列印 每張圖片的base64碼
Log.e(TAG, "callback: 壓縮方法" + encode(photos.get(number)));
}
});
}
/**
* 方法1
*/
private String encode(String path) {
Bitmap bitmap = BitmapFactory.decodeFile(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] bytes = baos.toByteArray();
//這裡有4種模式 defalut 是不連續的 me後臺接不到
//NO_WRAP 是連續的 還有2種在這就不做解釋了
byte[] encode = Base64.encode(bytes, Base64.NO_WRAP);
String encodeString = new String(encode);
return encodeString;
}
//msg 請求的結果
private String msg;
/**
* 圖片上傳
*/
private void testUploadFile(String url, String userId, String title, String content, String icons) {
//4個對應的引數 使用者id、標題、內容、拼接的圖片地址
RequestParams params = new RequestParams(url);
params.addBodyParameter("userId", userId);
params.addBodyParameter("title", title);
params.addBodyParameter("content", content);
params.addBodyParameter("icons", icons);
x.http().post(params, new Callback.CacheCallback<String>() {
@Override
public void onSuccess(String result) {
try {
JSONObject object = new JSONObject(result);
//返回狀態
String status = object.optString("status");
//返回的訊息
msg = object.optString("msg");
//成功關閉進度框
progressdialog.dismiss();
//200 說明成功
if (status.equals("200")) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
//記錄從點選到結束的所花時間 (可刪除)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss ");
Date curDate = new Date(System.currentTimeMillis());//獲取當前時間
String str = formatter.format(curDate);
Log.e(TAG, "UploadImageBase6結束時間: " + str);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
//失敗也要關閉對話方塊
progressdialog.dismiss();
Log.e(TAG, "onError: ");
}
@Override
public void onCancelled(CancelledException cex) {
Log.e(TAG, "onCancelled: ");
}
@Override
public void onFinished() {
Log.e(TAG, "onFinished456: " + msg);
}
@Override
public boolean onCache(String result) {
Log.e(TAG, "onCache: ");
return false;
}
});
}
/**
* 圖片上傳
* 地址,圖片集、圖片名稱、type(預設為2)
*/
private int number = 0;
private String status, data;
private StringBuffer sb = new StringBuffer();
private void UploadFile(String url, String userId, String icon, String type) {
//專門接收base64 的介面 使用者id、圖片、type與上面一致 只是為了區別(可刪除)
RequestParams params = new RequestParams(url);
params.addBodyParameter("userId", userId);
params.addBodyParameter("icon", icon);
params.addBodyParameter("type", type);
x.http().post(params, new Callback.CacheCallback<String>() {
@Override
public void onSuccess(String result) {
try {
JSONObject object = new JSONObject(result);
status = object.optString("status");
data = object.optString("data");
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
Log.e(TAG, "onError: " + status);
}
@Override
public void onCancelled(CancelledException cex) {
Log.e(TAG, "onCancelled: ");
}
@Override
public void onFinished() {
//說明上傳成功
if (status.equals("200")) {
//當圖片大於1張是,進行分隔
if (photos.size() > 1) {
sb.append("," + data);
} else {
//等於一張時不用
sb.append(data);
}
//每上傳完一張遞增加1
number++;
//在此調取上傳圖片介面
UploadImageBase64();
}
Log.e(TAG, "onFinished: " + photos.size() + "\n" + sb);
}
@Override
public boolean onCache(String result) {
Log.e(TAG, "onCache: ");
return false;
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && (requestCode == PhotoPicker.REQUEST_CODE ||
requestCode == PhotoPreview.REQUEST_CODE)) {
photos = null;
if (data != null) {
//獲取圖片的list
photos = data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS);
}
//清除list
selectedPhotos.clear();
if (photos != null) {
//新增至list中
selectedPhotos.addAll(photos);
}
//重新整理介面卡
photoAdapter.notifyDataSetChanged();
}
}
}
3.
package com.helloworld.base64demo;
import android.content.Context;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import java.io.File;
import java.util.ArrayList;
import me.iwf.photopicker.utils.AndroidLifecycleUtils;
public class PhotoAdapter extends RecyclerView.Adapter<PhotoAdapter.PhotoViewHolder> {
private ArrayList<String> photoPaths = new ArrayList<String>();
private LayoutInflater inflater;
private Context mContext;
public final static int TYPE_ADD = 1;
public final static int TYPE_PHOTO = 2;
final static int MAX = 9;
public PhotoAdapter(Context mContext, ArrayList<String> photoPaths) {
this.photoPaths = photoPaths;
this.mContext = mContext;
inflater = LayoutInflater.from(mContext);
}
@Override
public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = null;
switch (viewType) {
case TYPE_ADD:
itemView = inflater.inflate(R.layout.item_add, parent, false);
break;
case TYPE_PHOTO:
//包裡面的
itemView = inflater.inflate(R.layout.__picker_item_photo, parent, false);
break;
}
return new PhotoViewHolder(itemView);
}
@Override
public void onBindViewHolder(final PhotoViewHolder holder, final int position) {
if (getItemViewType(position) == TYPE_PHOTO) {
Uri uri = Uri.fromFile(new File(photoPaths.get(position)));
boolean canLoadImage = AndroidLifecycleUtils.canLoadImage(holder.ivPhoto.getContext());
if (canLoadImage) {
Glide.with(mContext)
.load(uri)
.centerCrop()
.thumbnail(0.1f)
.placeholder(R.drawable.__picker_ic_photo_black_48dp)
.error(R.drawable.__picker_ic_broken_image_black_48dp)
.into(holder.ivPhoto);
}
}
}
@Override
public int getItemCount() {
int count = photoPaths.size() + 1;
if (count > MAX) {
count = MAX;
}
return count;
}
@Override
public int getItemViewType(int position) {
return (position == photoPaths.size() && position != MAX) ? TYPE_ADD : TYPE_PHOTO;
}
public static class PhotoViewHolder extends RecyclerView.ViewHolder {
private ImageView ivPhoto;
private View vSelected;
public PhotoViewHolder(View itemView) {
super(itemView);
ivPhoto = (ImageView) itemView.findViewById(R.id.iv_photo);
vSelected = itemView.findViewById(R.id.v_selected);
if (vSelected != null) vSelected.setVisibility(View.GONE);
}
}
}
4.
package com.helloworld.base64demo;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
/**
* 點選事件 刪除
*/
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildLayoutPosition(childView));
return true;
}
return false;
}
@Override public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
step6: 2個佈局
1.activity_main.xml
2.item_add.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:paddingBottom="12dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:paddingTop="12dp"/>
<TextView
android:id="@+id/release_submit"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginBottom="70dp"
android:layout_marginLeft="22dp"
android:layout_marginRight="22dp"
android:layout_marginTop="70dp"
android:background="#666"
android:gravity="center"
android:text="釋出"
android:textColor="#fff"/>
</LinearLayout>
2.
<?xml version="1.0" encoding="utf-8"?>
<me.iwf.photopicker.widget.SquareItemLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:background="@drawable/xinxi_tupian"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</me.iwf.photopicker.widget.SquareItemLayout>
Step7:結束
相關推薦
安卓Base64批量上傳至伺服器
Step1:整體過程 /** * 由於請求框架開始就是Xutils compile ‘org.xutils:xutils:3.3.36’ 不做更改 * 1.第三方的圖片選擇器(支援選擇多張圖片、預覽、刪除等) * 2.onActivityR
安卓端同時上傳文字和圖片到伺服器,伺服器接收並處理
(更簡單的方法,點選安卓端同時上傳圖片和文字,伺服器接收並處理(二)) 之前看了很多部落格,找到的無非就是要麼只上傳json,要麼只上傳圖片。碰了許多的壁,因此我這裡寫一下自己已經測試成功的程式碼。 Android端使用Post上傳圖片和json程式碼 注
安卓app端上傳檔案到springMVC伺服器端的問題
先上程式碼,上傳檔案的封裝工具類如下: import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; imp
安卓PHP介面上傳檔案到伺服器
<?php /** * Created by PhpStorm. * User: Adaministrator * Date: 2018/3/30 * Time: 21:24 */ //連結資料庫 $servername = "182.254.147.87";
nginx優化-利用nginx限制HTTP的請求方法--防止指令碼被上傳至伺服器執行該指令碼對系統的破壞
利用nginx限制HTTP的請求方法 $request_method --防止指令碼被上傳至伺服器執行該指令碼對系統的破壞 可以上傳檔案,但是不能讓指令碼檔案執行成功 例如:站點目錄下有一個/image目錄,這個目錄是使用者上傳的一些圖片,不能阻止使用者上傳圖片,但要阻止使用者用特殊的方法執行裡面的檔
java檔案上傳至伺服器與檔案的刪除
一、檔案上傳(到伺服器中)程式碼如下: /** * 上傳檔案 * @param file 檔案 * @param request HttpServletRequest * @return 返回檔案基本資訊 */
c#將本地檔案上傳至伺服器(內網)
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; u
laravel上傳至伺服器上出現Whoops, looks like something went wrong.
轉載:https://blog.csdn.net/pt1742395895/article/details/79722861 1.在本地能夠很好執行的laravel,上傳至伺服器就出現了這個問題“Whoops, looks like something
如何使用html5 canvas畫布對本地視訊進行截圖並上傳至伺服器
前端程式碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">
JAVA實現客戶端圖片上傳至伺服器(SSM)(不使用input 標籤使用,瀏覽器圖片直接上傳伺服器)
JAVA實現客戶端圖片上傳至伺服器(SSM)(不使用input 標籤使用,瀏覽器圖片直接上傳伺服器) 這是本人第一篇部落格 想著記錄一下平時學習的過程,也提供給和我一樣正在學習java的同學們!!(如果有不懂的同學歡迎留言 有時間一定回覆,寫的不好的地方請多包涵) * 開始: 首先要
HTML5 本地裁剪圖片並上傳至伺服器 canvas圖片上傳 canvas圖片裁剪
很多情況下使用者上傳的圖片都需要經過裁剪,比如頭像啊什麼的。但以前實現這類需求都很複雜,往往需要先把圖片上傳到伺服器,然後返回給使用者,讓使用者確定裁剪座標,傳送給伺服器,伺服器裁剪完再返回給使用者,來回需要 5 步。步驟繁瑣不說,當很多使用者上傳圖片的時候也很影響伺服器
多選本地相簿中的圖片並展示(仿QQ空間動態傳送頁面)上傳至伺服器
最近公司專案需要從本地上傳圖片到伺服器,直接去找才發現安卓居然還有這麼坑的時候,呼叫原生的只能選擇一張圖片,而且還沒有任何的細節優化,觸控圖片就直接返回了。這肯定不行啊!於是就在網上找啊找。。。找啊找。。。有很多都寫得花裡胡哨的看不懂,而且介面的UI也是low的不行。。終於
iOS Crash閃退日誌獲取和上傳至伺服器
如何獲取crash閃退日誌 -- 工具檢視 先看第一個問題如何檢視,我搜索的方法有以下幾個: 第一個方法:XCode 的選單Window->Organizer 選擇Devices -> 選中的手機 -> 點選手機名稱左邊的箭頭 會等到如下
安卓選擇圖片上傳功能【支援多選拍照預覽等】
在網上找了很多第三方的相簿拍照框架,都不盡人意,最後終於找到了一個比較好的框架,並且整合到了自己的demo中,花了兩天的時間吧感覺挺值的。老規矩不說廢話,直接上程式碼。 感謝某開源庫的作者:Alum 思路 目錄 先看目錄,我儘可能的在自己力所能及的範圍
tp5上傳至伺服器中出現各類錯誤的解決方法
1.連線Mysql提示1045 access denied for user 'root'@'localhost' using password yes的解決方法檢查上傳至伺服器中的tp5中的database.php中的連線資料庫的密碼是否正確2.連線Mysql提示Can’t
HTML5 本地裁剪圖片並上傳至伺服器(老梗)
很多情況下使用者上傳的圖片都需要經過裁剪,比如頭像啊什麼的。但以前實現這類需求都很複雜,往往需要先把圖片上傳到伺服器,然後返回給使用者,讓使用者確定裁剪座標,傳送給伺服器,伺服器裁剪完再返回給使用者,來回需要 5 步。步驟繁瑣不說,當很多使用者上傳圖片的時候也很影響伺服器效
iOS Crash閃退日誌的捕獲和上傳至伺服器
今天我要講的是app的閃退資訊的捕獲,以及日誌上傳。 涉及的技術點 異常處理 捕獲方式 訊號量 閃退日誌上傳 在APP開發中,對於開發者或者使用者最不能接受的bug就是APP崩潰,所以對於APP閃退的問題追蹤非常重要,有利於儘快的修復這個問題。現在
iOS中(相簿)攝像頭獲取的圖片上傳至伺服器被自動旋轉了
今天寫專案的時候發現, 通過相機(相簿)獲取到的圖片顯示是正的,但是上傳至伺服器後下次從伺服器讀取就被莫名其妙的旋轉了,開始時候以為是伺服器的原因,最後原來是我的原因:如果把通過相機獲取到的圖片,直接進行操作, 比如裁剪, 縮放, 則會把原圖片向右旋轉90度。 上網查後
webapi批量上傳照片到ftp服務器(base64)
指定 rem pass adl ace bapi bsp 需求 所在 一段demo。做的時候根據自己的需求改造下 public HttpResponseMessage AddVisitNew(HttpRequestMessage request, CustomerVisi
Java Springboot結合FastDFS實現檔案上傳以及根據圖片url將圖片上傳至圖片伺服器
上一篇文章我們已經講解了如何搭建FastDFS圖片伺服器,環境我們準備好了現在就讓我們開始與Java結合將他應用到實際的專案中吧。本篇文章我們將會展示上傳圖片到FastDFS圖片伺服器以及通過外網的圖片url將圖片上傳至我們自己的圖片伺服器中。 1.建立springbo