springboot接受安卓传来的多张图片至阿里云CentOS服务器本地并被读取
后台
参考点+依赖
多图片保存在本地服务器
参考《springboot保存图片到项目文件资源路径》
修改点:多图片保存在本地服务器的确定路径,同时压缩图片保证图片不过大导致读取服务器图片时加载过慢。
压缩
《Thumbnails 压缩后反而变大》可知,用jpg转成jpg效果最佳
使用方法
Thumbnails.of("原图存放地址")
.scale(1f)
.outputQuality(0.5f)
.toFile("压缩后存放地址");
依赖:
<!-- 压缩图片-->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
<!-- 图片压缩Unsupported Image Type异常 引入以下依赖可解决-->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.6</version>
</dependency>
读取图片的方式:tomcat
参考《图片上传到Linux服务器的指定路径后,如何以外链的形式访问图片呢?》
与springboot的定义的文件目录需对应对应tomcat中添加
<Context docBase ="/home/images/" path ="/images" debug ="0" reloadable ="true"/>
springboot
private String staticPath="/home"; //定义上传文件的根目录
@ResponseBody
@RequestMapping(value ="/loadimages", method = RequestMethod.POST)
public AnswerRet<String> uploadImageByVisits(@RequestParam("files") List<MultipartFile> files, Long id) {
if(files==null)
throw new RrException(55500,"file 空");
else{
File targetFile = new File(staticPath);
if (!targetFile.exists()){
targetFile.mkdirs();
}
StringBuffer stringBuffer=new StringBuffer();
for(int i=0;i<files.size();i++){
//文件名:随机数+当前时间+格式
Random r = new Random();
int randomI = r.nextInt(1000);
Date date=new Date();
String fileName ="/"+date.getTime()+randomI+".jpg";
String url_path = "/images" + fileName;
//图片保存路径
String savePath = staticPath + url_path;
System.out.println("图片保存地址:"+savePath);
// 访问路径=静态资源路径+文件目录路径
String visitPath ="http://host:端口号" + url_path;
System.out.println("图片访问uri:"+visitPath);
File saveFile = new File(savePath);
if (!saveFile.exists()){
saveFile.mkdirs();
}
try {
files.get(i).transferTo(saveFile); //将临时存储的文件移动到真实存储路径下
//压缩
Thumbnails.of(savePath)
.scale(1f)
.outputQuality(0.5f)
.toFile(savePath);
stringBuffer.append(visitPath+",");
} catch (IOException e) {
throw new RrException(555551, e.getMessage());
}
}
if(stringBuffer.length()<=1)
throw new RrException(555550,"图片上传异常");
String url = stringBuffer.substring(0, stringBuffer.length() - 1);
//url 插入数据库中,读取时则得到url,由逗号隔开来查看图片
}
return new AnswerRet<>(1,"成功");
}
服务器本地图片:
外网读取图片:
安卓上传多图片
效果:选择图片上传时,最多九张图片上传,点击图片可浏览,图片左上角有删除按钮,点击加号弹窗提示拍照/相册
【利用girdview展示选中的图片,在最后的位置固定为+图片,直至9张图充满girdview
girdview适配器
girdview的item 主要两项imageview 一个图片一个删除按钮
在适配器中装载图片并确定删除按钮点击事件:
public class PhotoChooseListAdapter extends BaseAdapter {
//List<LocalMedia> 图片选择器选择后回调可返回的数据 即选中的list
private List<LocalMedia> selectList;
private LayoutInflater layoutInflater;
private Context context;
public PhotoChooseListAdapter(List<LocalMedia> selectList,Context context){
this.selectList=selectList;
this.context=context;
layoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return selectList.size() + 1;
}
@Override
public Object getItem(int i) {
return selectList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int position, View view, ViewGroup viewGroup) {
ViewHolder viewHolder = null;
if (view == null) {
viewHolder = new ViewHolder();
view = layoutInflater.inflate(girdview的item, viewGroup, false);
viewHolder.addimage = (ImageView) view.findViewById(R.id.photo_img);
viewHolder.photo_delete=(ImageView) view.findViewById(R.id.photo_delete);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
if (position == selectList.size()) {
//加号图标展示
Glide.with(context)
.load(R.drawable.add_photo)
.into(viewHolder.addimage);
if (position == 9) {
//加号图标消失
viewHolder.addimage.setVisibility(View.GONE);
}
viewHolder.photo_delete.setVisibility(View.GONE);
} else {
//正常展示图片,带上删除按钮
viewHolder.photo_delete.setVisibility(View.VISIBLE);
viewHolder.photo_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
selectList.remove(position);
setList(selectList);
notifyDataSetChanged();
}
});
//图片加载
String path;
if (selectList.get(position).isCompressed())
path=selectList.get(position).getCompressPath();
else if(selectList.get(position).isCut())
path=selectList.get(position).getCutPath();
else
path=selectList.get(position).getPath();
Glide.with(context)
.load(path)
.into(viewHolder.addimage);
}
return view;
}
public void setList(List<LocalMedia> selectList){
this.selectList=selectList;
}
class ViewHolder {
ImageView addimage;
ImageView photo_delete;
}
}
绑定适配器确定点击item监听事件,i==selectList.size() :点击加号按钮弹窗提示选择拍照/相册
否则 浏览图片
// 浏览图片
PictureSelector.create(VisitsAddActivity.this)
.themeStyle(com.luck.picture.lib.R.style.picture_default_style)
.isNotPreviewDownload(true)//是否显示保存弹框
.imageEngine(GlideEngine.createGlideEngine()) // 选择器展示不出图片则添加
.openExternalPreview(i, selectList);
弹窗
弹窗出现前,需动态获取权限
依赖
//动态获取权
implementation 'com.github.tbruyelle:rxpermissions:0.9.0'
final RxPermissions rxPermissions = new RxPermissions(VisitsAddActivity.this);
rxPermissions.request(Manifest.permission.RECORD_AUDIO,Manifest.permission.WRITE_EXTERNAL_STORAGE
,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean granted) {
if (granted) { // 在android 6.0之前会默认返回true
//打开弹窗
} else {
Toast.makeText(VisitsAddActivity.this, "拒绝", Toast.LENGTH_SHORT).show();
}
}
});
图片选择器
参考《Android 多图选择器PictureSelector 使用》
按上述链接完成缺少依赖glide的GlideEngine
解决方法:《关于Pictureselector相册全白、不显示图片的问题(附GlideEngine代码)》
打开相册举例:
private List<LocalMedia> selectList, 存放确定后回调返回的选中的图片list,每次打开相册和拍照都要带上
PictureSelector.create(VisitsAddActivity.this)
.openGallery(PictureMimeType.ofImage())
.selectionData(selectList)
.maxSelectNum(9)
.minSelectNum(1)
.imageEngine(GlideEngine.createGlideEngine())
.imageSpanCount(3)
.isPreviewImage(false)
.selectionMode(PictureConfig.MULTIPLE)
.isCamera(false)
.imageFormat(PictureMimeType.PNG)
.circleDimmedLayer(true)
.isEnableCrop(false)
.isCompress(true)
.showCropFrame(false)
.showCropGrid(false)
.rotateEnabled(false)
.scaleEnabled(true)
.isGif(false)
.minimumCompressSize(100)
.synOrAsy(true)
.forResult(PictureConfig.CHOOSE_REQUEST);
回调
PictureSelector.obtainMultipleResult(data)返回 List<LocalMedia> 即选中的图片赋值给selectList,直接动态修改gridview的高度。
发出请求
安卓请求规格化看前文 【Android】安卓实现网络请求,得到数据并显示于listview,包含token与拦截器
ApiService中
@POST("loadimages")
Call<ResponseBody> loadImages(@Body RequestBody requestBody);
请求调用
MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
for(int i=0;i<selectList.size();i++){
File file=new File(selectList.get(i).getRealPath());
selectList.get(i).getRealPath().replaceAll("\\\\", "/");
bodyBuilder.addFormDataPart("files",file.getAbsolutePath(),
RequestBody.create(MediaType.parse("application/octet-stream"),
new File(file.getAbsolutePath())));
}
bodyBuilder.addFormDataPart("id",id);
RequestBody body = bodyBuilder.build();
Call<ResponseBody> responseBodyCall = apiServiceBusiness.uploadImageVisits(body);
responseBodyCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
String res=null;
try {
res=new String(response.body().bytes());
JSONObject jsonObject= JSON.parseObject(res);
if(Long.parseLong(jsonObject.get("code").toString())==1) {
//成功的操作
} else {
//返回码失败的操作
}
}catch (IOException e){
//读取返回数据失败的操作
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//请求失败的操作
}
});