Flutter上传多张图片

最近研究了几天上传图片,看了视频资料后上传一张图片是没问题了,自己有深究了一下一次上传多张图片的情况,自己琢磨出个思路~

首先引入依赖:image_picker,当然还有别的大家可以自行选择,有个multy_image_picker依赖也可以,是一次选择多张图片的~然后在你需要上传的文件中引入文件:import 'package:image_picker/image_picker.dart';和import 'dart:io';接下来是代码:

3月11日:更新上传照片和删除图片代码,下面是全部代码

import 'package:flutter/material.dart';

import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:Config.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:rflutter_alert/rflutter_alert.dart';

class SignCommitPage extends StatefulWidget {
  final arguments;

  SignCommitPage({Key key, this.arguments}) : super(key : key);
  _SignCommitPageState createState() => _SignCommitPageState(this.arguments);
}

class _SignCommitPageState extends State {
  final arguments;
  _SignCommitPageState(this.arguments);

  //控制listview滚动条
  ScrollController _controller = new ScrollController();
  //用来存放图片的容器
  List _img = new List();
  //File类型,用来上传图片
  File _image;
  //用来存放上传的图片返回的id,后面删除图片用
  List _imgId = new List();

  //输入框组件
  Widget _textFieldWidget () {
    //listview滚动条保持在最后
    Timer(Duration(milliseconds: 0), () => _controller.jumpTo(_controller.position.maxScrollExtent));
    return Container(
      padding: EdgeInsets.only(left: ScreenAdapter.width(20.0), right: ScreenAdapter.width(20.0)),
      child: Column(
        children: [
          Row(
            children: [
              this._img == null ? Expanded(
                flex: 1,
                child: Text(""),
              ) : Expanded(
                flex: 1,
                child: Container(
                  width: double.infinity,
                  height: ScreenAdapter.width(150.0),
                  child: ListView.builder(
                    controller: _controller,   //滚动条控制
                    shrinkWrap: true,
                    scrollDirection: Axis.horizontal,
                    itemCount: this._img.length,   //循环_img渲染出listview
                    itemBuilder: (context, index){
                      return InkWell(
                        child: Container(
                          width: ScreenAdapter.width(150.0),
                          height: ScreenAdapter.width(150.0),
                          margin: EdgeInsets.only(right: ScreenAdapter.width(10.0)),
                          decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(4.0),
                              border: Border.all(
                                style: BorderStyle.solid,
                                color: Colors.black26,
                              )
                          ),
                          //隐藏id值,删除图片时可以直接获取到对应图片id
                          child: Visibility(
                            visible: false,
                            replacement: Image.network(this._img[index], fit: BoxFit.cover,),
                            child: Text(this._imgId[index]),
                          )
                        ),
                        //长按删除图片
                        onLongPress: (){
                          Alert(
                            context: context,
                            type: AlertType.info,
                            title: "确定删除这张照片吗?",
                            buttons: [
                              DialogButton(
                                child: Text(
                                  "确定",
                                  style: TextStyle(color: Colors.white, fontSize: 20),
                                ),
                                onPressed: () async {
                                  //删除图片方法,将要删除的图片名称和id传递过来
                                  _deleteImg(this._img[index], this._imgId[index]);
                                  Navigator.of(context).pop();
                                },
                              ),
                              DialogButton(
                                child: Text(
                                  "取消",
                                  style: TextStyle(color: Colors.white, fontSize: 20),
                                ),
                                onPressed: () => Navigator.of(context).pop(),
                              )
                            ],
                          ).show();
                        },
                      );
                    },
                  ),
                ),
              ),
              InkWell(
                child: Container(
                  width: ScreenAdapter.width(150.0),
                  height: ScreenAdapter.width(150.0),
                  margin: EdgeInsets.only(right: ScreenAdapter.width(10.0)),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(4.0),
                      border: Border.all(
                        style: BorderStyle.solid,
                        color: Colors.black26,
                      )
                  ),
                  child: Center(
                    child: Icon(Icons.camera_alt),
                  ),
                ),
                onTap: _openGallery,
              )
            ],
          )
        ]
      )
    );
  }

  //选择相册照片&上传
  void _openGallery () async {
    var imageUrl = await ImagePicker.pickImage(source: ImageSource.gallery, maxHeight: ScreenAdapter.width(150.0), maxWidth:ScreenAdapter.width(150.0));
    setState(() {
      //将获取到的图片路径赋给_image,上传
      this._image = imageUrl;
    });
    //上传开始
    String path = imageUrl.path;
    //获取文件名
    String imgName = path.substring(path.lastIndexOf("/") + 1, path.length);
    //获取格式
    String suffix = imgName.substring(imgName.lastIndexOf(".") + 1, imgName.length);
    FormData formData = new FormData.from({
      "userId" : "123456",
      "file" : new UploadFileInfo(this._image, imgName)
    });
    var res = await Dio().post("${Config.domain}uploadImg", data: formData);
    if (res.data["success"]) {
      Fluttertoast.showToast(
          msg: "${res.data["message"]}",
          gravity: ToastGravity.CENTER,
          timeInSecForIos: 3
      );
      setState(() {
        //将返回的图片路径和对应id添加到_img和_imgId中
        this._img.add("${Config.domain}" + "${res.data["data"]}");
        this._imgId.add("${res.data["id"]}");
      });
    } else {
      Fluttertoast.showToast(
          msg: "${res.data["message"]}",
          gravity: ToastGravity.CENTER,
          timeInSecForIos: 3
      );
    }
  }

  //删除图片
  void _deleteImg (img, id) async {
    //请求后端方法
    var api = "${Config.domain}deleteImg?id=" + id;
    var res = await Dio().get(api);
    if (res.data["success"]) {
      Fluttertoast.showToast(
          msg: "${res.data["message"]}",
          gravity: ToastGravity.CENTER,
          timeInSecForIos: 3
      );
      //成功的话将该图片和对应id分别从_img和_imgId中移除
      setState(() {
        this._img.remove(img);
        this._imgId.remove(id);
      });
    } else {
      Fluttertoast.showToast(
          msg: "${res.data["message"]}",
          gravity: ToastGravity.CENTER,
          timeInSecForIos: 3
      );
    }
  }

  //页面
  @override
  Widget build(BuildContext context) {
    ScreenAdapter.init(context);
    return Scaffold(
      appBar: AppBar(
        leading: InkWell(
          child: Icon(Icons.keyboard_return),
          onTap: (){
            Navigator.pop(context);
          },
        ),
        title: Text("上传图片"),
      ),
      body: ListView(
        children: [
          _textFieldWidget(),
        ],
      ),
    );
  }
}



//Config.dart
class Config {
  //域名定义成自己的即可
  static String domain = "http://www.haha.com/";
}

后端代码,小编的后端是java:

//直接用@RestController了,前后端分离直接返回json数据就好了
@RestController
//一定要有这个注解,下面讲作用
@MultipartConfig
public class AppController {
    //引包小编就不贴了,现在编程软件一般都有提示
    @Autowired
    private HttpServletRequest request;

    //上传图片
    String filesPath = "";
    @RequestMapping(value = "/uploadImg", method = RequestMethod.POST)
    public AppResult uploadImg (HttpServletRequest request) {
        try {
            //此处要提到上面@MultipartConfig注解了,flutter向后端post数据时,一般的字符串数据可以直接通过request.getParameter("xxx")获取到,但是无法获取图片,获取为null
            //此处和request.getParameter("xxx")一样,你传的文件的key
            Part part = request.getPart("file");
            //获取文件名
            String fileNames = getFileName(part);
            //这里小编把文件重命名了一下,以免重名
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmsssss");
            String id = sdf.format(new Date());
            String[] splitName = fileNames.split("\\.");
            String finalName = id + "." + splitName[splitName.length - 1];
            //上传文件
            filesPath = writeTo(finalName, part);
            //这里可以实现你自己的逻辑,可以与数据库交互等等
            return AppResult.success(true, "上传成功", 返回图片路径, 返回图片id);
        } catch (IOException ie) {
            ie.printStackTrace();
            return AppResult.error(false, "网络错误,请稍后重试");
        } catch (ServletException se) {
            se.printStackTrace();
            return AppResult.error(false, "上传失败,请稍后重试");
        }
    }

    //获取文件名
    private String getFileName(Part part) {
        String head = part.getHeader("Content-Disposition");
        String fileName = head.substring(head.indexOf("filename=\"")+10, head.lastIndexOf("\""));
        return fileName;
    }

    //写文件
    private String writeTo(String finalName, Part part) throws IOException {
        String path = request.getSession().getServletContext().getRealPath("/uploadAppVisit");
        if (!new File(path).exists() || !new File(path).isDirectory()) {
            new File(path).mkdirs();
        }
        InputStream in = part.getInputStream();
        OutputStream out = new FileOutputStream(path + "/" + finalName);
        byte[] b = new byte[1024];
        int length = -1;
        while((length = in.read(b)) != -1){
            out.write(b, 0, length);
        }
        in.close();
        out.close();
        return finalName;
    }

    //删除图片
    @RequestMapping(value = "/deleteImg", produces={"application/json;charset=UTF-8"})
    public AppResult deleteImg (String id) {
        try {
            //这里是删除方法,换成自己的
            hahaService.deleteById(id);
            return AppResult.ok(true, "删除成功", "");
        } catch (Exception e) {
            e.printStackTrace();
            return AppResult.error(false, "删除失败请重试");
        }
    }
}



//AppResult.java,这里定义一个实体类用来返回结果,避免每个方法都要自己写一遍,也方便修改
public class AppResult {
    private boolean success;
    private String message;
    private Object data;
    private String id;

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public AppResult (boolean success, String message) {
        this.success = success;
        this.message = message;
    }

    public AppResult (boolean success, String message, Object data) {
        this.success = success;
        this.message = message;
        this.data = data;
    }

    public AppResult (boolean success, String message, Object data, String id) {
        this.success = success;
        this.message = message;
        this.data = data;
        this.id = id;
    }

    public static AppResult ok (boolean success, String message, Object data) {
        return new AppResult(success, message, data);
    }

    public static AppResult success (boolean success, String message, Object data, String id) {
        return new AppResult(success, message, data, id);
    }

    public static AppResult error (boolean success, String message) {
        return new AppResult(success, message);
    }
}

 

//同时上传多张照片获取方法,有时间把上传照片详细代码更上来
Collection parts = request.getParts();
if (parts.size()>0) {
    String str="";
    for (Part part : parts) {
        if (part.getName().startsWith("file")) {
            String fileNames = getFileName(part);
            String path = writeTo(fileNames, part);
            str += xxx;
        }
    }
}

选择图片实现,如下图:

选择图片前:Flutter上传多张图片_第1张图片

选择图片后:

Flutter上传多张图片_第2张图片

到这里选择图片上传和删除图片全部实现,各位可以直接拿走使用,里面还有个地图定位的功能这里没写,在这篇https://blog.csdn.net/Gemini_Kanon/article/details/104628500博客里有~如果哪里代码有错误搞不出来可以联系小编帮忙!

这些代码是小编自己琢磨加找资料编写的,如果有错误请指出,哪位兄台有更好的方法小编想随时虚心请教~

你可能感兴趣的:(Flutter,Dart)