[Android]端末からサーバへ画像のアップロード

##はじめに
Androidで画像をPOSTし、サーバに保存する機能でてこずったため自分の備忘録兼、アウトプットとして書きます。プログラムのお仕事半年もしてないからいろいろおかしいかもしれないけど許してね。

###追記
ご指摘を受けました。ありがとうございます！
>OkHTTP2はobsoletes扱いです。最新の4.3.1を使うようにしましょう。

https://square.github.io/okhttp/changelog_3x/#version-300-rc1
https://square.github.io/okhttp/changelog/

##環境
AndroidStudioでOkHttpを利用しています。
##OkHttp導入
* AndroidStudio画面左上の「Android」を「プロジェクト」に切り替え。
* [app]内のbuild.gradleを開く。
* ~~dependencies内に 
```
implementation 'com.squareup.okhttp:okhttp:2.7.5'
```を追記。(2.7.5はvarsionによって変えてください。)~~
* dependencies内に``implementation 'com.squareup.okhttp:okhttp:4.3.1'
``を追記。
(2020/1/24　変更)

```gradle:build.gradle
//～～省略～～
dependencies{
  //～～省略～～
  implementation 'com.squareup.okhttp:okhttp:4.3.1'//追記
}
```
完了。

##AsyncTask
Http通信で送るので非同期で行う。

```java:OkHttpTask.java
import android.os.AsyncTask;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class HttpTask extends AsyncTask<String, Void, String> {

    String responseBody;
    public HttpTask(){}

    @Override
    protected String doInBackground(String... params) {
        String url = "送るURL"; 
        MediaType media = MediaType.parse("multipart/form-data");
        try {
            File file = new File(params[0]);
            String FileName = file.getName();
            String boundary = String.valueOf(System.currentTimeMillis());

            RequestBody requestBody = new MultipartBody.Builder(boundary).setType(MultipartBody.FORM)
                    .addFormDataPart("file", FileName, RequestBody.create(media, file))
                    .build();

            Request request = new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();

            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            responseBody = response.body().string();

            return responseBody;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return responseBody;
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d("a",result);
    }
}

```

いろいろ変更したので書き直しました。また、変更に伴って
``java.io.IOException: Cleartext HTTP traffic to example.com not permitted``
のようなエラーが表示されることがあるかと思います。
これはデフォルトでHTTPS通信になったので、HTTP通信を許可する方法を書いておく必要があるからです。方法については[こちら](https://qiita.com/b_a_a_d_o/items/afa0d83bbffdb5d4f6be)の方が詳しく書かれているのでどうぞ。

<details><summary>古いコード</summary><div>

```java:OkHttpTask_old.java
/**削除
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
*/
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class OkHttpTask extends AsyncTask<String, Void, String> {
  public OkHttpTask(){}

    @Override
    protected String doInBackground(String... params) {
        //ポスト先のURL
        String url = "http://";
        File file = new File(params[0]);

        /**削除
        *ここでPOSTする内容を設定
        RequestBody requestBody = new MultipartBuilder()
                .type(MultipartBuilder.FORM)
                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/jpg"), file))
                .build();
        */

        //ここでPOSTする内容を設定(こっちに変更)
        RequestBody requestBody = new MultipartBody.Builder()
                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/jpg"), file))
                .build();


        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        String result="";
        try {
            Response response = client.newCall(request).execute();
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
            {
                result = response.body().string();
            }
        } catch (Exception e) {}

        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d("end:",result);
    }
}
*/
```

</div></details>
##MainActivity
```java:MainActivity.java

public class MainActivity extends AppCompatActivity {
  //送る画像のURI
  private Uri _imageUri;
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //ここで呼び出し
        new OkHttpTask().execute(url);   
}
```
##受け取る側
Postされたファイルを保存するだけ。

```java:UpLoad.java
@WebServlet("/Upload")
@MultipartConfig(location = "保存場所")
public class upload extends HttpServlet {

	public void doPost(HttpServletRequest req,HttpServletResponse res) throws IOException, ServletException {
		String name="no_name";
		//multipart/form-dataによって提供されるこのリクエストのすべてのPart要素を取得
		for (Part part : req.getParts()) {
			//名前の取得
			for (String cd : part.getHeader("Content-Disposition").split(";")) {
				String str = cd.trim();
				if (str.startsWith("filename")) {
					String str2 = str.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
					File f = new File(str2);
					name = f.getName();
					part.write(name);
				}
			}
		}
	}
}
```
##参考リンク
OkHttpを初めて使ってみた話
https://qiita.com/LyricalMaestro0/items/698c77f5a964b5658bbb