我有问题,我想通过使用Laravel和Flutter上传多个图像,但我不知道如何
在Mysql数据库中,我有三个表:“用户和公寓”表和“照片中的照片”表具有三个字段:id,公寓_id,url
因此,在照片表中,我应该显示具有特定照片所有公寓,这意味着公寓表和照片表之间存在一对多关系
那么如何解决呢?
我试着写代码在Laravel在PhotoController
我从网上得到这个代码
{
$request->validate([
'apartment_id' => 'required|exists:apartments,id',
'images' => 'required|array',
'images.*' => 'image|mimes:jpeg,png,jpg|max:2048',
]);
$apartmentId = $request->input('apartment_id');
$images = $request->file('images');
$uploadedImageIds = [];
foreach ($images as $image) {
$path = $image->store('your_directory');
$photo = new Photo();
$photo->apartment_id = $apartmentId;
$photo->url = $path;
$photo->save();
$uploadedImageIds[] = $photo->id;
}
return response()->json(['message' => 'Images uploaded successfully', 'image_ids' => $uploadedImageIds]);
}
我有一个代码在抖动
此代码来自互联网
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http/http.dart' as http;
// import 'package:video_player/video_player.dart';
class AddImages extends StatefulWidget {
const AddImages({super.key, this.title});
final String? title;
@override
State<AddImages> createState() => _AddImagesState();
}
class _AddImagesState extends State<AddImages> {
List<XFile>? _imageFileList;
void _setImageFileListFromFile(XFile? value) {
_imageFileList = value == null ? null : <XFile>[value];
}
dynamic _pickImageError;
String? _retrieveDataError;
final ImagePicker _picker = ImagePicker();
final TextEditingController maxWidthController = TextEditingController();
final TextEditingController maxHeightController = TextEditingController();
final TextEditingController qualityController = TextEditingController();
Future<void> _onImageButtonPressed(ImageSource source,
{BuildContext? context, bool isMultiImage = false}) async {
if (isMultiImage) {
await _displayPickImageDialog(context!,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final List<XFile> pickedFileList = await _picker.pickMultiImage(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
);
setState(() {
_imageFileList = pickedFileList;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
} else {
await _displayPickImageDialog(context!,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final XFile? pickedFile = await _picker.pickImage(
source: source,
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
);
setState(() {
_setImageFileListFromFile(pickedFile);
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
}
}
@override
void dispose() {
// _disposeVideoController();
maxWidthController.dispose();
maxHeightController.dispose();
qualityController.dispose();
super.dispose();
}
Widget _previewImages() {
final Text? retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_imageFileList != null) {
return Semantics(
// label: 'image_picker_example_picked_images',
child: GridView.builder(
key: UniqueKey(),
itemBuilder: (BuildContext context, int index) {
// Why network for web?
// See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform
return Stack(children: [
Image.file(
File(
_imageFileList![index].path,
),
height: 110,
width: 110,
fit: BoxFit.cover,
),
Positioned(
left: 15.0,
top: 2,
child: GestureDetector(
child: const Icon(
Icons.cancel,
color: Colors.white70,
),
onTap: (){
setState(() {
_imageFileList!.removeAt(index);
});
},
))
]);
},
itemCount: _imageFileList!.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 5,
crossAxisSpacing: 5,
// childAspectRatio: 0,
// mainAxisExtent: 5
),
),
);
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'تُعرض الصور المختارة هنا',
style: TextStyle(fontFamily: 'IBM'),
textAlign: TextAlign.center,
);
}
}
Widget _handlePreview() {
return _previewImages();
}
Widget? checkArray() {
if (_imageFileList != null) {
Get.to(FourthStep());
} else {
}
return null;
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await _picker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
setState(() {
if (response.files == null) {
_setImageFileListFromFile(response.file);
} else {
_imageFileList = response.files;
}
});
} else {
_retrieveDataError = response.exception!.code;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade200,
appBar: AppBar(
backgroundColor: Colors.white,
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text(" رجوع "),
),
),
const Expanded(child: Text("")),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: checkArray,
child: const Text("تم"),
),
),
],
),
body: Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 0),
child: Center(
child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android
? FutureBuilder<void>(
future: retrieveLostData(),
builder:
(BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'',
style: TextStyle(
fontFamily: 'IBM',
),
textAlign: TextAlign.center,
);
case ConnectionState.done:
return _handlePreview();
case ConnectionState.active:
if (snapshot.hasError) {
return Text(
': خطأ ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'',
textAlign: TextAlign.center,
);
}
}
},
)
: _handlePreview(),
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_onImageButtonPressed(
ImageSource.gallery,
context: context,
isMultiImage: true,
);
},
heroTag: 'image0',
backgroundColor: Colors.orange,
tooltip: 'أضف صور من المعرض',
child: const Icon(Icons.photo_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_onImageButtonPressed(ImageSource.camera, context: context);
},
heroTag: 'image1',
tooltip: 'إلتقط صورة',
backgroundColor: Colors.orange,
child: const Icon(Icons.camera_alt),
),
),
],
),
);
}
Text? _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError!);
_retrieveDataError = null;
return result;
}
return null;
}
Future<void> _displayPickImageDialog(
BuildContext context, OnPickImageCallback onPick) async {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text(
'إضافة صور للشقة',
style: TextStyle(
fontFamily: 'IBM',
),
),
actions: <Widget>[
ElevatedButton(
style: fullButton,
child: const Text('إضافة'),
onPressed: () {
final double? width = maxWidthController.text.isNotEmpty
? double.parse(maxWidthController.text)
: null;
final double? height = maxHeightController.text.isNotEmpty
? double.parse(maxHeightController.text)
: null;
final int? quality = qualityController.text.isNotEmpty
? int.parse(qualityController.text)
: null;
onPick(width, height, quality);
Navigator.of(context).pop();
}),
Padding(
padding: const EdgeInsets.fromLTRB(110, 0, 0, 0),
child: OutlinedButton(
child: const Text(
'رجوع',
),
onPressed: () {
Navigator.of(context).pop();
},
),
),
],
);
});
}
//for testing
//---------------------------------------------------
Future<void> uploadImages(List<XFile> imageFiles) async {
var request = http.MultipartRequest(
'POST',
Uri.parse('http://10.0.2.2:8000/api/photo/uploadImages'),
);
for (var imageFile in imageFiles) {
var multipartFile = await http.MultipartFile.fromPath(
'images[]',
imageFile.path,
);
request.files.add(multipartFile);
}
var response = await request.send();
if (response.statusCode == 200) {
print('Images uploaded successfully');
} else {
print('Image upload failed with status ${response.statusCode}');
}
}
//---------------------------------------------------
}
typedef OnPickImageCallback = void Function(
double? maxWidth, double? maxHeight, int? quality);
1条答案
按热度按时间atmip9wb1#
我知道如果你想实现没有外部依赖(像dio这样的包)的唯一方法是http.MultipartRequest。
}
你也可以使用dio来实现同样的功能。
根据官方文件: