JavaRush /جاوا بلاگ /Random-UR /فائلوں کو ایپلیکیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹ...

فائلوں کو ایپلیکیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا بیس میں محفوظ کرنا

گروپ میں شائع ہوا۔
فائلوں کو ایپلیکیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا بیس میں محفوظ کرنا - 1 آئیے تصور کریں کہ آپ اپنی ویب ایپلیکیشن پر کام کر رہے ہیں۔ میں اپنے مضامین میں اس موزیک کے انفرادی ٹکڑوں کو دیکھتا ہوں، جیسے: یہ موضوعات کیسے مفید ہیں؟ اور حقیقت یہ ہے کہ یہ مثالیں حقیقی پروجیکٹس پر کام کرنے کے بہت قریب ہیں، اور ان موضوعات کی جانچ آپ کے لیے بہت مفید ثابت ہوگی۔ آج ہم اس موزیک کا اگلا حصہ لیں گے - فائلوں کے ساتھ کام کرنا، کیونکہ آج کل آپ کو ایسی سائٹ نہیں مل سکتی جو ان کے ساتھ تعامل نہ کرتی ہو (مثال کے طور پر، ہر قسم کی ویب شاپس، سوشل نیٹ ورک وغیرہ)۔ جائزہ اپ لوڈ/ڈاؤن لوڈ/ڈیلیٹ کرنے کے طریقوں کا استعمال کرتے ہوئے ایک مثال کے طور پر کیا جائے گا ؛ ہم اسے اپنی درخواست میں ایک فولڈر (وسائل میں) میں محفوظ کریں گے، تاکہ یہ پیچیدہ نہ ہو۔ فائلوں کو ایپلیکیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا بیس میں محفوظ کرنا - 2خیال یہ ہے کہ ہم اپنے نام نہاد فائل اسٹوریج میں فائل کے علاوہ، ہمارے ڈیٹا بیس میں ہماری فائل (سائز، نام، وغیرہ) کے بارے میں معلومات کے ساتھ ایک ہستی کو محفوظ کریں گے - ایک پہلے سے تیار کردہ ٹیبل۔ یعنی فائل لوڈ کرتے وقت یہ ہستی ہمارے لیے بہت کارآمد ثابت ہوگی اور ڈیلیٹ کرتے وقت ہمیں اس کے بارے میں کسی بھی طرح سے فراموش نہیں کرنا چاہیے۔ آئیے اس ٹیبل پر ایک نظر ڈالتے ہیں: فائلوں کو ایپلی کیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا کو ڈیٹا بیس میں محفوظ کرنا - 3اور آئی ڈی کو بڑوں کی طرح AUTO_INCREMENT پر سیٹ کرتے ہیں، تاکہ ڈیٹا بیس کی سطح پر خود بخود ایک شناخت کنندہ تیار کیا جا سکے۔ سب سے پہلے، آئیے اپنی ساخت پر ایک نظر ڈالتے ہیں: فائلوں کو ایپلی کیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا کو ڈیٹا بیس میں محفوظ کرنا - 4اوپر دکھائے گئے جدول کے نیچے موجود ہستی:
@Builder(toBuilder = true)
@Getter
@ToString
public class FileInfo {

   private Long id;

   private String name;

   private Long size;

   private String key;

   private LocalDate uploadDate;
}

اپ لوڈ کریں۔

آئیے کنٹرولر کو دیکھیں:
@RestController
@RequestMapping("/file")
@RequiredArgsConstructor
public class FileController {

   private final FileService fileService;

   @PostMapping
   public ResponseEntity<FileInfo> upload(@RequestParam MultipartFile attachment) {
       try {
           return new ResponseEntity<>(fileService.upload(attachment), HttpStatus.CREATED);
       } catch (IOException e) {
           return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
       }
   }
دلچسپ چیزیں: 9 - ہم فائل کو فارم میں قبول کرتے ہیں MultipartFile۔ یہ بائٹس کی ایک صف کے طور پر بھی وصول کیا جا سکتا ہے، لیکن مجھے یہ آپشن زیادہ پسند ہے، کیونکہ ہم MultipartFileمنتقل شدہ فائل کی مختلف خصوصیات کو نکال سکتے ہیں۔ 10 - 14 - ہم اپنے اعمال کو try catchاس طرح لپیٹ دیتے ہیں کہ اگر نچلی سطح پر کوئی استثناء واقع ہوتا ہے، تو ہم اسے اوپر بھیج دیتے ہیں اور جواب کے طور پر 400 غلطی بھیج دیتے ہیں۔ اگلا سروس کی سطح ہے:
public interface FileService {

   FileInfo upload(MultipartFile resource) throws IOException;
آئیے نفاذ کو دیکھتے ہیں:
@Service
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {

   private final FileDAO fileDAO;
   private final FileManager fileManager;

   @Transactional(rollbackFor = {IOException.class})
   @Override
   public FileInfo upload(MultipartFile resource) throws IOException {
       String key = generateKey(resource.getName());
       FileInfo createdFile = FileInfo.builder()
               .name(resource.getOriginalFilename())
               .key(key)
               .size(resource.getSize())
               .build();
       createdFile = fileDAO.create(createdFile);
       fileManager.upload(resource.getBytes(), key);

       return createdFile;
   }
8 - IOException کی صورت میں، ڈیٹا بیس میں ہماری تمام بچتیں واپس کر دی جائیں گی۔ 11 - ہم ایک کلید تیار کرتے ہیں جو فائل کے محفوظ ہونے پر منفرد ہو گی (اگر چہ ایک ہی نام کی دو فائلیں محفوظ ہو جائیں تو کوئی الجھن نہیں ہوگی)۔ 12 - ہم ڈیٹا بیس میں محفوظ کرنے کے لیے ایک ہستی بناتے ہیں۔ 17 — ہم ڈیٹا بیس میں معلومات کے ساتھ ہستی کو چلاتے ہیں۔ 18 - ہیشڈ نام کے ساتھ فائل کو محفوظ کریں۔ 20 — ہم تخلیق شدہ ہستی واپس کرتے ہیں FileInfo، لیکن ڈیٹا بیس میں تیار کردہ آئی ڈی کے ساتھ (اس پر ذیل میں بات کی جائے گی) اور تخلیق کی تاریخ۔ فائل کی کلید بنانے کا طریقہ:
private String generateKey(String name) {
   return DigestUtils.md5Hex(name + LocalDateTime.now().toString());
}
یہاں ہم نے نام + تخلیق کی تاریخ ہیش کی ہے، جو ہماری انفرادیت کو یقینی بنائے گی۔ ڈاؤ پرت انٹرفیس:
public interface FileDAO {

   FileInfo create(FileInfo file);
اس کا نفاذ:
@Repository
@RequiredArgsConstructor
public class FileDAOImpl implements FileDAO {

   private static final String CREATE_FILE = "INSERT INTO files_info(file_name, file_size, file_key, upload_date) VALUES (?, ?, ?, ?)";

   private final JdbcTemplate jdbcTemplate;

   @Override
   public FileInfo create(final FileInfo file) {
       LocalDate uploadDate = LocalDate.now();
       GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
       jdbcTemplate.update(x -> {
           PreparedStatement preparedStatement = x.prepareStatement(CREATE_FILE, Statement.RETURN_GENERATED_KEYS);
           preparedStatement.setString(1, file.getName());
           preparedStatement.setLong(2, file.getSize());
           preparedStatement.setString(3, file.getKey());
           preparedStatement.setDate(4, Date.valueOf(uploadDate));
           return preparedStatement;
       }, keyHolder);

       return file.toBuilder()
               .id(keyHolder.getKey().longValue())
               .uploadDate(uploadDate)
               .build();
   }
11 - ایک تاریخ بنائیں جسے ہم محفوظ کریں گے۔ 12 - 21 - ہم ہستی کو محفوظ کرتے ہیں، لیکن زیادہ پیچیدہ انداز میں، آبجیکٹ کی واضح تخلیق کے ساتھ PreparedStatementتاکہ تیار کردہ آئی ڈی کو نکالا جا سکے (یہ اسے علیحدہ درخواست کے ساتھ نہیں، بلکہ جوابی میٹا ڈیٹا کی شکل میں نکالتا ہے۔ )۔ 22 - 26 - ہم اپنی دیرینہ ہستی کی تعمیر مکمل کرتے ہیں اور اسے سب سے اوپر دیتے ہیں (حقیقت میں، وہ اسے مکمل نہیں کرتا، بلکہ ایک نئی چیز بناتا ہے، منتقل شدہ فیلڈ کو بھرتا ہے اور باقی کو اصل سے نقل کرتا ہے) . آئیے دیکھتے ہیں کہ ہماری فائلیں اس میں کیسے محفوظ ہوں گی FileManager:
public void upload(byte[] resource, String keyName) throws IOException {
   Path path = Paths.get(DIRECTORY_PATH, keyName);
   Path file = Files.createFile(path);
   FileOutputStream stream = null;
   try {
       stream = new FileOutputStream(file.toString());
       stream.write(resource);
   } finally {
       stream.close();
   }
}
1 - ہم فائل کو بائٹس کی ایک صف کے طور پر قبول کرتے ہیں اور الگ سے وہ نام جس کے تحت اسے محفوظ کیا جائے گا (ہماری تیار کردہ کلید)۔ 2 - 3 - ایک راستہ بنائیں (اور راستے میں ہم راستہ اور اپنی کلید لکھتے ہیں) اور اس کے ساتھ ایک فائل۔ 6 - 7 - ایک اسٹریم بنائیں اور وہاں ہمارے بائٹس لکھیں (اور اس بات کو یقینی بنانے کے لیے یہ تمام چیزیں لپیٹ دیں try-finallyکہ یہ سلسلہ یقینی طور پر بند ہوجائے گا)۔ تاہم، بہت سے طریقے IOException کو پھینک سکتے ہیں۔ اس صورت میں، میتھڈ ہیڈر میں بتائی گئی فارورڈنگ کی بدولت، ہم اسے کنٹرولر کو بھیجیں گے اور اسٹیٹس 400 دیں گے۔ آئیے پوسٹ مین میں پوری چیز کی جانچ کرتے ہیں: فائلوں کو ایپلیکیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا کو ڈیٹا بیس میں محفوظ کرنا - 5جیسا کہ آپ دیکھ سکتے ہیں، سب کچھ ٹھیک ہے، جواب 201 ہے، جواب JSON ڈیٹا بیس میں ہماری مستقل ہستی کی شکل میں آیا، اور اگر ہم اپنے اسٹوریج کو دیکھیں: DB: فائلوں کو ایپلی کیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا کو ڈیٹا بیس میں محفوظ کرنا - 6ہم دیکھتے ہیں کہ ہمارے پاس ایک نئی قدر ہے۔ (=*;*=)

ڈاؤن لوڈ کریں

کنٹرولر:
@GetMapping(path = "/{id}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> download(@PathVariable("id") Long id) {
   try {
       FileInfo foundFile = fileService.findById(id);
       Resource resource = fileService.download(foundFile.getKey());
       return ResponseEntity.ok()
               .header("Content-Disposition", "attachment; filename=" + foundFile.getName())
               .body(resource);
   } catch (IOException e) {
       return new ResponseEntity<>(HttpStatus.NOT_FOUND);
   }
}
ہم اسے بھی لپیٹ دیتے ہیں try-catchاور IOException کی صورت میں ہم 404 رسپانس اسٹیٹس بھیجتے ہیں (نہیں ملا)۔ 4 - ڈیٹا بیس سے ملحقہ فائل انفو ہستی کو نکالیں۔ 5 - ادارے کی کلید کا استعمال کرتے ہوئے، فائل 6-8 ڈاؤن لوڈ کریں - فائل کو واپس بھیجیں، فائل کا نام ہیڈر میں شامل کریں (دوبارہ، فائل کے بارے میں معلومات کے ساتھ ہستی سے حاصل کی گئی)۔ آئیے ایک گہرا جائزہ لیتے ہیں۔ سروس انٹرفیس:
Resource download(String key) throws IOException;

FileInfo findById(Long fileId);
نفاذ:
@Override
public Resource download(String key) throws IOException {
   return fileManager.download(key);
}

@Transactional(readOnly = true)
@Override
public FileInfo findById(Long fileId) {
   return fileDAO.findById(fileId);
}
یہاں کچھ خاص طور پر دلچسپ نہیں ہے: آئی ڈی کے ذریعہ کسی ہستی کو تلاش کرنے اور فائل کو ڈاؤن لوڈ کرنے کا طریقہ، سوائے شاید 46 کے - ہم نشان زد کرتے ہیں کہ ہمارے پاس پڑھنے کا لین دین ہے۔ داؤ کی سطح:
FileInfo findById(Long fileId);
نفاذ:
private static final String FIND_FILE_BY_ID = "SELECT id, file_name, file_size, file_key, upload_date FROM files_info WHERE id = ?";

@Override
public FileInfo findById(Long fileId) {
   return jdbcTemplate.queryForObject(FIND_FILE_BY_ID, rowMapper(), fileId);
}

private RowMapper<FileInfo> rowMapper() {
   return (rs, rowNum) -> FileInfo.builder()
           .id(rs.getLong("id"))
           .name(rs.getString("file_name"))
           .size(rs.getLong("file_size"))
           .key(rs.getString("file_key"))
           .uploadDate(rs.getObject("upload_date", LocalDate.class))
           .build();
}
4 - id استعمال کرکے تلاش کریں jdbcTemplateاور RowMapper. 8 - 15 - RowMapperڈیٹا بیس اور ماڈل فیلڈز سے ڈیٹا کا موازنہ کرنے کے لیے، ہمارے مخصوص کیس کے لیے عمل درآمد۔ چلیں FileManagerاور دیکھتے ہیں کہ ہماری فائل کیسے لوڈ ہوتی ہے:
public Resource download(String key) throws IOException {
   Path path = Paths.get(DIRECTORY_PATH + key);
   Resource resource = new UrlResource(path.toUri());
   if (resource.exists() || resource.isReadable()) {
       return resource;
   } else {
       throw new IOException();
   }
}
ہم فائل کو بطور آبجیکٹ واپس کرتے ہیں Resource، اور ہم کلید کے ذریعے تلاش کریں گے۔ 3 - Resourceراستے + کلید کے ساتھ بنائیں۔ 4 - 8 - ہم چیک کرتے ہیں کہ دیئے گئے راستے پر موجود فائل خالی نہیں ہے اور اسے پڑھتے ہیں۔ اگر سب کچھ ٹھیک ہے، تو ہم اسے واپس کر دیتے ہیں، اور اگر نہیں، تو ہم ایک IOException کو اوپر پھینک دیتے ہیں۔ آئیے پوسٹ مین میں اپنا طریقہ چیک کریں: فائلوں کو ایپلی کیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا کو ڈیٹا بیس میں محفوظ کرنا - 7جیسا کہ ہم دیکھ سکتے ہیں، اس نے ٹھیک کام کیا))

حذف کریں۔

@DeleteMapping(value = "/{id}")
public ResponseEntity<Void> delete(@PathVariable("id") Long id) {
   try {
       fileService.delete(id);
       return new ResponseEntity<>(HttpStatus.OK);
   } catch (IOException e) {
       return new ResponseEntity<>(HttpStatus.NOT_FOUND);
   }
}
یہاں کچھ خاص نہیں ہے: استعمال کرنے میں ناکامی کی صورت میں ہم 404 بھی واپس کرتے ہیں try-catch۔ سروس انٹرفیس:
void delete(Long fileId) throws IOException;
نفاذ:
@Transactional(rollbackFor = {IOException.class})
@Override
public void delete(Long fileId) throws IOException {
   FileInfo file = fileDAO.findById(fileId);
   fileDAO.delete(fileId);
   fileManager.delete(file.getKey());
}
1 - IOException ہونے پر ڈیٹا کی تبدیلیوں (حذف کرنے) کا بھی رول بیک۔ 5 - ڈیٹا بیس سے فائل کے بارے میں معلومات کو حذف کریں۔ 6 - فائل کو ہمارے "اسٹوریج" سے ہی ڈیلیٹ کر دیں۔ داو انٹرفیس:
void delete(Long fileId);
نفاذ:
private static final String DELETE_FILE_BY_ID = "DELETE FROM files_info WHERE id = ?";

@Override
public void delete(Long fileId) {
   jdbcTemplate.update(DELETE_FILE_BY_ID, fileId);
}
ایسا کچھ نہیں ہے - صرف حذف کریں۔ فائل کو خود ہی حذف کرنا:
public void delete(String key) throws IOException {
       Path path = Paths.get(DIRECTORY_PATH + key);
       Files.delete(path);
   }
}
ہم پوسٹ مین کا استعمال کرتے ہیں: فائلوں کو ایپلی کیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا کو ڈیٹا بیس میں محفوظ کرنا - 8ہم اسٹوریج میں دیکھتے ہیں: فائلوں کو ایپلیکیشن میں محفوظ کرنا اور ان کے بارے میں ڈیٹا کو ڈیٹا بیس میں محفوظ کرنا - 9خالی :) اب ڈیٹا بیس میں: Сохранение файлов в приложение и данных о них на БД - 10ہم دیکھتے ہیں کہ سب کچھ اچھا ہے))

پرکھ

آئیے اپنے لیے ایک ٹیسٹ لکھنے کی کوشش کرتے ہیں FileManager۔ سب سے پہلے، ٹیسٹ کے حصے کی ساخت پر ایک نظر ڈالتے ہیں: mockFile.txt وہ فائل ہے جس کے ساتھ ہم فائل اسٹوریج کے ساتھ اپنے آپریشنز کی جانچ کریں گے۔ testFileStorage ہمارے اسٹوریج کا متبادل ہوگا۔ FileManagerTest:
public class FileManagerTest {

   private static MultipartFile multipartFile;

   private static FileManager manager;

   private static FileInfo file;

   @BeforeClass
   public static void prepareTestData() throws IOException {
       file = FileInfo.builder()
               .id(9L)
               .name("mockFile.txt")
               .key("mockFile.txt")
               .size(38975L)
               .uploadDate(LocalDate.now())
               .build();
       multipartFile = new MockMultipartFile("mockFile", "mockFile.txt", "txt",
               new FileInputStream("src/test/resources/mockFile.txt"));
       manager = new FileManager();
   }
یہاں ہم ٹیسٹ ڈیٹا اسائنمنٹ دیکھتے ہیں۔ فائل سیونگ ٹیسٹ:
@Test
public void uploadTest() throws IOException {
   ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/testFileStorage/");

   manager.upload(multipartFile.getBytes(), "mockFile.txt");

   Path checkFile = Paths.get("src/test/resources/testFileStorage/mockFile.txt");
   assertThat(Files.exists(checkFile)).isTrue();
   assertThat(Files.isRegularFile(checkFile)).isTrue();
   assertThat(Files.size(checkFile)).isEqualTo(multipartFile.getSize());
   Files.delete(checkFile);
}
3 - ٹیسٹ ریفلیکشن کا استعمال کرتے ہوئے، ہم فائل کو محفوظ کرنے کا راستہ سیٹ کرنے کے لیے سروس میں اپنا مستقل تبدیل کرتے ہیں۔ 5 - جانچے جانے والے طریقہ کو کال کریں۔ 7 - 10 - سیو کے صحیح عمل کو چیک کریں۔ 11 - محفوظ کردہ فائل کو حذف کریں (ہمیں کوئی نشان نہیں چھوڑنا چاہئے)۔
@Test
public void downloadTest() throws IOException {
   ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/");

   Resource resource = manager.download(file.getKey());

   assertThat(resource.isFile()).isTrue();
   assertThat(resource.getFilename()).isEqualTo(file.getName());
   assertThat(resource.exists()).isTrue();
}
فائل اپ لوڈ ٹیسٹ: 3 - دوبارہ، ہمارے لیے راستہ تبدیل کریں FileManager۔ 5 - جس طریقہ کا تجربہ کیا جا رہا ہے اسے استعمال کریں۔ 7 - 9 - پھانسی کا نتیجہ چیک کریں۔ فائل ڈیلیٹ کرنے کا ٹیسٹ:
@Test
public void deleteTest() throws IOException {
   Path checkFile = Paths.get("src/test/resources/testFileStorage/mockFile.txt");
   Files.createFile(checkFile);
   assertThat(Files.exists(checkFile)).isTrue();
   assertThat(Files.isRegularFile(checkFile)).isTrue();
   ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/testFileStorage/");

   manager.delete(file.getKey());

   assertThat(Files.notExists(checkFile)).isTrue();
}
9 - 3 - 4 - راستہ طے کریں اور فائل بنائیں۔ 5 - 6 - ہم اس کے وجود کی جانچ کرتے ہیں۔ 9 - ہم ایک قابل تصدیق طریقہ استعمال کرتے ہیں۔ 77 - ہم چیک کرتے ہیں کہ وہ چیز اب موجود نہیں ہے۔ اور آئیے دیکھتے ہیں کہ انحصار کے لحاظ سے ہمارے پاس کیا ہے:
<dependencies>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-jdbc</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <scope>test</scope>
       <exclusions>
           <exclusion>
               <groupId>org.junit.vintage</groupId>
               <artifactId>junit-vintage-engine</artifactId>
           </exclusion>
       </exclusions>
   </dependency>
   <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <version>1.18.10</version>
       <scope>provided</scope>
   </dependency>
   <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>8.0.18</version>
   </dependency>
   <dependency>
       <groupId>commons-codec</groupId>
       <artifactId>commons-codec</artifactId>
       <version>1.9</version>
   </dependency>
   <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.13-rc-2</version>
       <scope>test</scope>
   </dependency>
</dependencies>
آج میرے لیے اتنا ہی ہے))
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION