android+spring boot 選擇,上傳,下載文件

1 概述

前端android,上傳與下載文件,使用OkHttp處理請求,後端使用spring boot+MVC,處理android發送來的上傳與下載請求.這個其實不難,就是特別多奇奇怪怪的坑,所以,但願看到的,不要像筆者這樣踩的那麼痛苦了...css

2 環境

  • win10
  • Spring Boot 2.2.2 RELEASE
  • IDEA 2019.3.1
  • Android Studio 3.6RC1
  • Tomcat 9.0.30

3 android

3.1 準備工做

3.1.1 新建工程

此次用一個全新的例子寫博客,所以重新建工程開始:前端

在這裏插入圖片描述

在這裏插入圖片描述

3.1.2 AndroidManifest.xml

加入java

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:usesCleartextTraffic="true">

網絡權限,讀寫SD卡權限,固然還有容許http請求的權限.linux

3.1.3 build.gradle

加入android

compileOptions {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
}

這個是支持JDK8的.
還有這兩個okhttp與conscrypt,最新版本okhttp能夠在這裏查看,最新版本conscrypt在這裏:git

implementation 'com.squareup.okhttp3:okhttp:4.3.1'
implementation 'org.conscrypt:conscrypt-android:2.2.1'

3.1.4 上傳文件

手動上傳一些文件到AVD設備,爲下一步選擇與上傳文件作準備,先把這個窗口工具欄打開:github

在這裏插入圖片描述

打開後,打開在右側欄中的Device File Explorer:web

在這裏插入圖片描述

而後選擇sdcard文件夾上傳文件便可,其餘文件夾通常沒有權限.spring

在這裏插入圖片描述

3.1.5 佈局

添加三個button(上傳/下載/選擇文件),一個EditText(上傳文件名與下載文件名),一個ImageView(顯示下載的圖片).apache

在這裏插入圖片描述

直接拖放改一下id.

3.2 選擇文件

3.2.1 申請權限

首先申請動態讀寫文件權限(其實選擇文件只須要讀權限,由於後面的下載須要寫權限因此這裏就一塊兒申請了):

在這裏插入圖片描述

使用checkSelfPermission檢查權限,參數爲一個Context與String,String表示相應的權限,若是有了這個權限就會返回

PackageManager.PERMISSION_GRANTED

沒有就會返回

PackageManager.PERMISSION_DENIED

沒有就利用requestPermissions()申請,參數爲Content,String[],int,String[]表示要申請的全部權限,int是一個requestCode.

3.2.2 Intent選擇文件

在這裏插入圖片描述

新建一個Intent後,設置選擇類型,而後就重寫onActivityResult:

在這裏插入圖片描述

這是簡化了的處理,由於選擇的是圖片,選擇其餘文件的話能夠參照這裏.

其中path是選擇的文件的路徑,可能你會問:

String path = dir.toString().substring(0,dir.toString().indexOf("0")+2) +
    DocumentsContract.getDocumentId(uri).split(":")[1];

這個是怎麼來的,實際上是拼湊過來的,由於這是圖片,是這個的簡化版:

在這裏插入圖片描述

(博客在這裏)

3.3 上傳文件

在這裏插入圖片描述

參數爲文件路徑與文件名,而後使用OkHttpClient,由於是文件,用的body是MultipartBody,增長一個叫file的FormDataPart與一個叫filename的FormDataPart.而後使用execute()發送請求,body()獲取響應內容,這裏假設了後端響應一個布爾,表示上傳成功或失敗,url的話使用了本地的路徑,注意不能是localhost,使用內網ip,而後還要與後端對應.

3.4 下載文件

在這裏插入圖片描述

參數爲一個文件名,根據這個文件名返回對應的文件,返回一個File,這裏請求體能夠選擇FormBody或MultipartBody,由於這是一個文件名參數,這裏筆者爲了統一就選擇了MultipartBody,使用FormBody的話,只須要將RequestBody的那一行改成:

RequestBody body = new FormBody.Builder().add("filename",filename).build();

有了請求體後發送請求獲取響應體,進而獲取輸入流,而後首先須要判斷是否爲空,但不能直接這樣判斷:

inputStream == null

由於後端是這樣的:

在這裏插入圖片描述

從響應體獲取的inputStream確定不爲null,須要先進行一次讀取(也就是判斷裏面的文件是否爲null),若爲null的話刪除這個文件,不爲null的話繼續讀取並寫入文件.

4 Spring Boot

4.1 準備工做

用的是IDEA,其餘IDE請自行搜索如何新建一個SpringBoot工程.

4.1.1 新建工程

在這裏插入圖片描述

打包的話能夠jar或war,不用部署的話jar便可,要部署的話後期也能夠改爲war.

在這裏插入圖片描述

兩個,一個Spring Web,用於MVC等,一個模板引擎,用於顯示視圖,若是不須要顯示能夠不選.

在這裏插入圖片描述

4.1.2 application.properties

做爲一個示例demo,屬性就直接在application.properties中配置了,實際狀況請在相應的配置文件中配置相應屬性.

在這裏插入圖片描述

須要配置上傳文件的大小限制與上傳文件夾的路徑.

4.1.3 pom.xml

這裏其實不須要幹什麼,只是若是下載依賴慢的話,能夠這樣設置settings.xml文件,在<mirrors>中加上:

<mirror>
    <id>alimaven</id>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <mirrorOf>central</mirrorOf>
</mirror>

<mirror>
    <id>uk</id>
    <mirrorOf>central</mirrorOf>
    <name>Human Readable Name for this Mirror.</name>
    <url>http://uk.maven.org/maven2/</url>
</mirror>

<mirror>
    <id>CN</id>
    <name>OSChina Central</name>
    <url>http://maven.oschina.net/content/groups/public/</url>
    <mirrorOf>central</mirrorOf>
</mirror>

<mirror>
    <id>nexus</id>
    <name>internal nexus repository</name>
    <!-- <url>http://192.168.1.100:8081/nexus/content/groups/public/</url>-->
    <url>http://repo.maven.apache.org/maven2</url>
    <mirrorOf>central</mirrorOf>
</mirror>

windows用戶的話這個文件在

C:\Users\{username}\.m2\settings.xml

linux的話在

~/.m2/settings.xml

4.2 處理上傳文件

在這裏插入圖片描述

首先對應的post映射路徑爲/upload,與android端的路徑對應,而後須要一個表示文件的MultipartFile與一個表示文件名的String,判斷這兩個是否爲空後,若是上傳的文件夾不存在則先建立,存在的話直接進行復制,而後根據複製成功或失敗返回布爾值.複製使用了Files.copy(),第一個InputStream爲上傳文件的輸入流,第二個Path爲存儲文件的路徑,resolve(filename)至關於在上傳目錄下的filename文件.輸出的話建議使用日誌代替.

4.3 處理下載文件

下載的話能夠選擇使用get或post請求,這裏選擇了post請求,由於android端是post請求,須要對應.get請求的話能夠從瀏覽器發起.

在這裏插入圖片描述

首先根據文件名獲取對應文件,判斷文件是否存在後返回一個ResponseEntity,須要設定content-type與body,content-type根據須要設置便可,這裏是圖片,默認.jpg或.png,body的話使用FileSystemResource,直接new一個放進body便可.

若是不存在相應的文件則返回null,這裏須要注意一下前端的判斷,不能直接判斷ResponseBody是否爲null.

5 測試

5.1 postman測試

postman只能測試與後端的鏈接,上傳等是否有問題,能夠用來定位後端的問題.

5.1.1 上傳測試

再Headers中設置了Content-Type爲multipart/form-data後:

在這裏插入圖片描述

在body添加一個叫file的文件與一個叫filename的字符串表示文件名:

在這裏插入圖片描述

發送,返回true.

在這裏插入圖片描述

服務器端有輸出提示:

在這裏插入圖片描述

查看文件夾:

在這裏插入圖片描述

5.1.2 下載測試

把file參數關掉,保留filename,修改路徑.

在這裏插入圖片描述

而後發送,postman能夠直接顯示圖片:

在這裏插入圖片描述

5.2 android端測試

5.2.1 上傳測試

在這裏插入圖片描述

後端提示:

在這裏插入圖片描述

查看文件夾:

在這裏插入圖片描述

5.2.2 下載測試

輸入文件名後直接下載:

在這裏插入圖片描述

默認的話是放在這裏,按須要更改位置便可,注意加上寫權限:

在這裏插入圖片描述

若看不到文件選擇synchronize便可.

在這裏插入圖片描述

6 部署到服務器

服務器用的是tomcat,須要修改一些Spring Boot的部分.

6.1 部署

6.1.1 改變打包方式

pom.xml中jar改爲war.

在這裏插入圖片描述

6.1.2 去除tomcat依賴

pom.xml加入:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

6.1.3 修改Main

修改Main類,讓其繼承SpringBootServletInitializer,重載configure(),同時main()保持不變.

修改前:

在這裏插入圖片描述

修改後:

在這裏插入圖片描述

6.1.4 修改路徑

這個按須要修改便可,在這裏不須要,注意就是@PostMapping,@GetMapping等都是相對於

tomcat/webapps/項目/

目錄下的.

6.1.5 設置打包名字

build加上<finalName>.

在這裏插入圖片描述

6.1.6 打包

在這裏插入圖片描述

6.1.7 上傳到服務器

打包後的文件放在target下,使用scp上傳便可,這裏是本地的tomcat,就這接移動war了.

6.1.8 運行

開啓tomcat,雙擊startup.bat便可.

在這裏插入圖片描述

linux的話:

cd xxxx/tomcat/bin
./startup.sh

6.2 測試

在測試前須要確保沒有佔用相應端口,默認8080,也就是說,若是不改端口的話,須要關閉IDEA運行中的SpringBoot應用.

6.2.1 postman測試

上傳測試,注意須要改路徑,加上打包項目名,ip的話可使用localhost或者內網ip.

在這裏插入圖片描述

服務器這邊收到了,由於上傳路徑只是直接寫名字,所以會與startup.bat同一路徑.

在這裏插入圖片描述

下載測試:

在這裏插入圖片描述

服務器的輸出:

在這裏插入圖片描述

6.2.2 android端測試

android端須要修改路徑便可,加上war打包的名字.

在這裏插入圖片描述

這裏打包的名字是kr,直接加上便可.

在這裏插入圖片描述

上傳那裏也是要加上,而後:

在這裏插入圖片描述

服務器的輸出:

在這裏插入圖片描述

查看文件:

在這裏插入圖片描述

7 最最最喜歡的

7.1 權限

android須要讀權限才能讀取文件並上傳,須要寫權限才能保存從服務器返回的文件,在AndroidManifest.xml中加入:

<manifest>...
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>...</application>

這是外部設備的讀寫權限.固然,加入這個還不能訪問,由於,android6.0之後還須要動態申請權限,因此:

String [] permission = new String[]{
    "android.permission.READ_EXTERNAL_STORAGE",
    "android.permission.WRITE_EXTERNAL_STORAGE"
};
if(
    ActivityCompat.checkSelfPermission(this,permission[0]) != PackageManager.PERMISSION_GRANTED
    ||
    ActivityCompat.checkSelfPermission(this,permission[1]) != PackageManager.PERMISSION_DENIED
)
{
    ActivityCompat.requestPermissions(this,permission,1);
}

7.2 路徑

須要保證下面幾個路徑正確,還有可讀,可寫等:

  • url路徑不能錯.
  • 前端上傳文件的路徑.
  • 後端接收前端上傳文件的路徑.
  • 後端發送前端須要下載的文件的路徑.
  • 前端接收下載文件的路徑.

7.3 有關http的問題

7.3.1 okhttp的stream關閉

在這裏插入圖片描述

若前端是這樣寫的,在工具類中返回了以後Response已經關閉,所以須要讀取輸入流之類的須要先讀取再返回,而不是返回一個ResponseBody或InputStream進行讀取,不然會提示"closed".

7.3.2 http

Android P開始默認禁用http,所以可使用https或者在AndroidManifest.xml中容許http鏈接:

<application android:usesCleartextTraffic="true">

7.3.3 線程

網絡請求不能在主線程中,新開一個線程便可.

7.3.4 AVD

若檢查過了服務器與android端沒問題,那麼有多是AVD的問題,解決方法很簡單,卸載,重啓AVD,注意必定要卸載再重啓.

7.4 ip

在本地測試的話後端能夠直接localhost,在android端不能直接localhost,可使用ipconfig或ifconfig查看內網ip,輸入內網ip便可.

在這裏插入圖片描述

若在服務器上測試直接使用服務器ip.

7.5 判空處理

對於前端,應該判斷存儲路徑是否爲空,是否爲null等,再傳給後端,對於後端,要判斷文件是否存在等,不存在就返回null,這時又須要前端進行判斷返回的null,在下載文件時,雖然對不存在的文件後端返回null,可是,前端收到的是一個InputStream,不能直接判斷是否爲null,須要先讀取一次,再進行剩下的讀取:

在這裏插入圖片描述

8 源碼

github

碼雲

相關文章
相關標籤/搜索