수업시간에 활용하기 위해 만든 자료를 올립니다.
Back-End : Spring Boot
Upload :
l 여러 파일 동시 업로드
l C:/upload 에 파일 write
l 파일 명은 upload 되는 파일명을 그대로 이용
Download :
l 클라이언트 request parameter 를 download 파일명으로 이용
@RestController
public class UploadController {
@PostMapping("/mobile/upload.do")
public String upload(@RequestParam("multipartFiles") List<MultipartFile> multipartFiles) throws IOException {
System.out.println("multipartFiles.size():"+multipartFiles.size());
for (MultipartFile multipartFile : multipartFiles) {
BufferedImage image = ImageIO.read(multipartFile.getInputStream());
String[] array = multipartFile.getContentType().split("/");
for(String data: array) {
System.out.println("array : "+data);
}
String filename = multipartFile.getOriginalFilename();
System.out.println("filename:"+filename);
String path = "C:/upload/" + filename;
File outputFile = new File(path);
ImageIO.write(image,"jpg",outputFile);
}
return "success";
}
@GetMapping(value="/mobile/download.do")
public ResponseEntity<ByteArrayResource> download(@RequestParam("filename") String filename) throws IOException {
System.out.println("download:"+filename);
Path path = Paths.get("C:/upload/"+filename);
byte[] data = Files.readAllBytes(path);
ByteArrayResource resource = new ByteArrayResource(data);
return ResponseEntity.ok()
// Content-Disposition
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + path.getFileName().toString())
// Content-Type
.contentType(MediaType.parseMediaType("image/jpeg")) //
// Content-Lengh
.contentLength(data.length) //
.body(resource);
}
}
Front-End : Android App
라이브러리 dependency
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.1'
implementation 'com.github.bumptech.glide:glide:4.12.0'
AndroidManifest.xml 설정
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Multiple Picker
Gallery 목록 화면 출력
val intent = Intent(
Intent.ACTION_GET_CONTENT,//extra_allow_multiple 이려면 action 문자열이 action_get_content
MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = "image/*"
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
requestGalleryLauncher.launch(intent)
선택한 이미지 화면 출력
선택한 이미지를 RecyclerView 를 이용해 가로 방향으로 나열
try {
if (it.data!!.data != null) {
Log.d("kkang","select one..................")
datas.add(it.data!!.data!!)
adapter.notifyDataSetChanged()
} else {
if (it.data!!.clipData != null) {
val mClipData: ClipData = it.data!!.clipData!!
Log.d("kkang","select count: ${mClipData.itemCount}")
for (i in 0 until mClipData.itemCount) {
val item = mClipData.getItemAt(i)
datas.add(item.uri)
}
adapter.notifyDataSetChanged()
}
}
} catch (e: Exception) {
e.printStackTrace()
}
이미지를 출력한 RecyclerView.Adapter 의 onBindViewHolder()
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
try {
val option = BitmapFactory.Options()
option.inSampleSize = 10
// 이미지 로딩
var inputStream = context.contentResolver.openInputStream(datas[position])
val bitmap = BitmapFactory.decodeStream(inputStream, null, option)
inputStream!!.close()
bitmap?.let {
holder.binding.itemImageView.setImageBitmap(bitmap)
} ?: let {
Log.d("kkang", "${datas[position]} ... bitmap null")
}
} catch (e: Exception) {
e.printStackTrace()
}
}
Upload
이미지 Uri 값을 이용, File Path 획득, File 객체 준비
datas.forEachIndexed { index, uri ->
var filePath = ""
val wholeID = DocumentsContract.getDocumentId(uri)
val id = wholeID.split(":").toTypedArray()[1]
val column = arrayOf(MediaStore.Images.Media.DATA)
val sel = MediaStore.Images.Media._ID + "=?"
val cursor: Cursor = contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, arrayOf(id), null
)!!
val columnIndex = cursor.getColumnIndex(column[0])
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex)
}
Log.d("kkang","filePath:$filePath")
fileList.add(File(filePath))
val segment = filePath.split("/")
fileNameArray[index] = segment.last()
cursor.close()
}
이미지 업로드를 위한 MultipartBody.Part 준비
val listPart = mutableListOf<MultipartBody.Part>()
fileList.forEach {
listPart.add(MultipartBody.Part.createFormData(
name = "multipartFiles",
filename = it.name,
body = it.asRequestBody("image/jpg".toMediaType())
))
}
Retrofit 을 이용한 Upload
interface UploadService {
@Multipart
@POST("upload.do")
fun uploadMultipleFiles(
@Part multipartFiles: List<MultipartBody.Part>
): Call<String>
}
val call = (applicationContext as MyApplication).apiService.uploadMultipleFiles(listPart)
call.enqueue(object : Callback<String> {
override fun onResponse(call: Call<String>, response: Response<String>) {
val result = response.body()!!
Log.d("kkang", "result................$result")
}
override fun onFailure(call: Call<String>, t: Throwable) {
t.printStackTrace()
call.cancel()
}
})
Download
Glide.with(context)
.load("http://10.0.2.2:8080/mobile/download.do?filename=${datas[position]}")
.into(holder.binding.itemImageView)
'Android' 카테고리의 다른 글
Datastore (0) | 2022.07.29 |
---|---|
Android JWT 인증 with Retrofit, Spring boot (0) | 2022.07.27 |
Android – Spring Boot Network Programming with Retrofit (0) | 2022.07.21 |
[깡쌤의 안드로이드 프로그래밍 with 자바 - 2022 - 쌤즈] 정리 25 - GoogleMap (0) | 2022.05.09 |
[깡쌤의 안드로이드 프로그래밍 with 자바 - 2022 - 쌤즈] 정리 24 - Retrofit2 구조 (0) | 2022.05.09 |