JavaRush /Java Blog /Random-TK /Faýllary programma we olar hakda maglumatlary maglumat ba...

Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak

Toparda çap edildi
Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 1 Web programmaňyzda işleýändigiňizi göz öňüne getireliň. Makalalarymda bu mozaikanyň aýry-aýry böleklerine seredýärin: Bu mowzuklar nähili peýdaly? Bu mysallaryň hakyky taslamalaryň üstünde işlemäge gaty ýakynlygy we bu mowzuklary synagdan geçirmek siziň üçin gaty peýdaly bolar. Bu gün bu mozaikanyň indiki bölegini alarys - faýllar bilen işlemek, sebäbi häzirki wagtda olar bilen täsirleşmeýän sahypa tapyp bilmersiňiz (mysal üçin, her dürli web dükany, sosial ulgam we ş.m.). Gözden geçirmek mysal hökmünde ýüklemek / göçürip almak / aýyrmak usullaryny ulanmak arkaly amala aşyrylar ; ony kynlaşdyrmazlyk üçin amalymyzdaky bukjada (çeşmede) saklarys. Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 2Bu pikir, faýl ammary diýlip atlandyrylýan faýldan başga-da, maglumatlar bazamyzda faýlymyz (ululygy, ady we ş.m.) maglumatlary bolan desgany - öňünden döredilen tablisany ýatda saklarys. .Agny, bir faýl ýüklenende, bu gurama bize gaty peýdaly bolar we öçürilende hiç hili ýatdan çykarmaly däldiris. Geliň, bu tablisa göz aýlalyň: Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 3we maglumatlar bazasy derejesinde awtomatiki kesgitleýji döretmek üçin ID-ni ulular ýaly AUTO_INCREMENT-e belläliň. Ilki bilen gurluşymyza göz aýlalyň: Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 4aboveokarda görkezilen tablisanyň aşagyndaky gurama:
@Builder(toBuilder = true)
@Getter
@ToString
public class FileInfo {

   private Long id;

   private String name;

   private Long size;

   private String key;

   private LocalDate uploadDate;
}

Uploadükle

Dolandyryja seredeliň:
@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);
       }
   }
Gyzykly zatlar: 9 - Faýly görnüşde kabul edýäris MultipartFile. Mundan başga-da, baýtlar toplumy hökmünde kabul edilip bilner, ýöne bu opsiýany has gowy görýärin, sebäbi MultipartFilegeçirilen faýlyň dürli häsiýetlerini çykaryp bileris. 10 - 14 - has try catchpes derejede kadadan çykma ýüze çyksa, has ýokary ugradarys we jogap hökmünde 400 ýalňyşlyk ibereris. Indiki hyzmat derejesi:
public interface FileService {

   FileInfo upload(MultipartFile resource) throws IOException;
Theerine ýetirilişine seredeliň:
@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 ýüze çykan halatynda maglumatlar bazasyndaky ähli tygşytlamalarymyz yzyna gaýtarylar. 11 - faýl ýatda saklananda özboluşly boljak açary döredýäris (birmeňzeş atlary bolan iki faýl ýatda saklansa-da, bulaşyklyk bolmaz). 12 - maglumat bazasynda saklamak üçin bir gurama gurýarys. 17 - maglumatlar bilen guramany maglumat bazasyna sürýäris. 18 - faýly ýuwulan at bilen ýazdyryň. 20 - döredilen guramany gaýtaryp berýäris FileInfo, ýöne maglumatlar bazasyndaky döredilen id bilen (aşakda serediler) we döredilen senesi. Faýlyň açaryny döretmegiň usuly:
private String generateKey(String name) {
   return DigestUtils.md5Hex(name + LocalDateTime.now().toString());
}
Bu ýerde özboluşlylygymyzy üpjün etjek ady + döredilen senesini basýarys. Dao gatlak interfeýsi:
public interface FileDAO {

   FileInfo create(FileInfo file);
Ony durmuşa geçirmek:
@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 - ýatda saklajak senämizi dörediň. 12 - 21 - döredilen ID-ni çykaryp bilmek üçin obýekti aç-açan döretmek bilen, has çylşyrymly görnüşde halas edýäris PreparedStatement(ony aýratyn haýyş bilen däl-de, jogap meta-maglumaty görnüşinde çykarýar) ). 22-25 . Faýllarymyzyň nädip ýatda saklanjakdygyny göreliň 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 - faýly baýtlar toplumy hökmünde we saklanjak adyny aýratynlykda kabul edýäris (döredilen açarymyz). 2 - 3 - bir ýol dörediň (we ýolda goşmaça açarymyzy ýazýarys) we onuň bilen bir faýl dörediň. 6 - 7 - akym dörediň we baýtlarymyzy şol ýere ýazyň (we try-finallyakymyň hökman ýapyljakdygyna göz ýetirmek üçin bu zatlaryň hemmesini örtüň). Şeýle-de bolsa, usullaryň köpüsi IOException-a zyňyp biler. Bu ýagdaýda, usul sözbaşysynda görkezilen ugradyşyň kömegi bilen ony dolandyryja geçireris we 400 status bereris. “Postman” -da ähli zady synap göreliň: Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 5Görşüňiz ýaly, hemme zat gowy, jogap 201, JSON jogap bazadaky dowamly guramamyz görnüşinde geldi we ammarymyza göz aýlasak: DB: muny Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 6görýäris biziň täze bahamyz bar. (= *; * =)

Göçürip al

Dolandyryjy:
@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);
   }
}
Şeýle hem, ony gurşap alýarys try-catchwe IOException bolan ýagdaýynda 404 jogap statusyny iberýäris (tapylmady). 4 - goňşy FileInfo guramasyny maglumat bazasyndan çykaryň. 5 - guramanyň açaryny ulanyp, 6-8 faýly göçürip alyň - faýlyň adyny sözbaşysyna goşup, faýly yzyna iberiň (ýene-de faýl hakda maglumat bilen guramadan alnan). Çuňňur göz aýlalyň. Hyzmat interfeýsi:
Resource download(String key) throws IOException;

FileInfo findById(Long fileId);
Durmuşa geçirmek:
@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);
}
Bu ýerde aýratyn gyzykly zat ýok: 46-dan başga, ID-den bir zady gözlemek we faýly göçürip almak usuly - okamak üçin geleşigimiziň bardygyny belleýäris. Dao derejesi:
FileInfo findById(Long fileId);
Durmuşa geçirmek:
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 ulanyp gözlemek jdbcTemplatewe RowMapper. 8-15 - RowMapperaýratyn ýagdaýymyz üçin, maglumatlar bazasyndan we model meýdanlaryndan maglumatlary deňeşdirmek üçin durmuşa geçirmek. Geliň, FileManagerfaýlymyzyň nähili ýüklenendigini göreliň:
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();
   }
}
Faýly obýekt hökmünde gaýtaryp berýäris Resourcewe açar bilen gözläris. 3 - Resourceýol + düwmesini dörediň. 4 - 8 - berlen ýolda faýlyň boş däldigini barlaýarys we okaýarys. Hemme zat gowy bolsa, yzyna gaýtaryp bereris, ýok bolsa IOException-y ýokarsyna zyňarys. Poçta bölüminde usulymyzy barlap göreliň: Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 7Görşümiz ýaly, gowy işledi))

Öçür

@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);
   }
}
Bu ýerde üýtgeşik zat ýok: ulanylmadyk ýagdaýynda 404-i hem gaýtaryp berýäris try-catch. Hyzmat interfeýsi:
void delete(Long fileId) throws IOException;
Durmuşa geçirmek:
@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 ýüze çykanda maglumatlaryň üýtgemegi (öçürilmegi). 5 - faýl hakda maglumatlary maglumat bazasyndan pozuň. 6 - faýly “ammarymyzdan” pozuň. dao interfeýsi:
void delete(Long fileId);
Durmuşa geçirmek:
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);
}
Munuň ýaly zat ýok - diňe poz. Faýlyň özi pozulýar:
public void delete(String key) throws IOException {
       Path path = Paths.get(DIRECTORY_PATH + key);
       Files.delete(path);
   }
}
Poçta ulanýarys: Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 8Ammarda seredýäris: Faýllary programma we olar hakda maglumatlary maglumat bazasyna ýazdyrmak - 9Boş :) Indi maglumatlar bazasynda: Сохранение файлов в приложение и данных о них на БД - 10Hemme zadyň gowydygyny görýäris))

Synag

Geliň, özümiz üçin synag ýazmaga synanyşalyň FileManager. Ilki bilen, synag böleginiň gurluşyna göz aýlalyň: mockFile.txt - bu amaly saklamak bilen amallarymyzy synagdan geçirjek faýl. testFileStorage ammarymyzyň ornuny tutar. 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();
   }
Bu ýerde synag maglumatlarynyň belligini görýäris. Faýl tygşytlamak synagy:
@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 - synag şöhlelenmesini ulanyp, faýly ýatda saklamagyň ýoluny kesgitlemek üçin hyzmatdaky üýtgewsizligimizi üýtgedýäris. 5 - synag edilýän usula jaň ediň. 7 - 10 - tygşytlylygyň dogry ýerine ýetirilişini barlaň. 11 - saklanan faýly pozuň (hiç hili yz galdyrmaly däldiris).
@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();
}
Faýl ýüklemek synagy: 3 - ýene-de biziň ýolumyzy üýtgediň FileManager. 5 - synag edilýän usuly ulanyň. 7 - 9 - ýerine ýetiriş netijesini barlaň. Faýly öçürmek synagy:
@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 - ýoly düzüň we faýl dörediň. 5 - 6 - barlygyny barlaýarys. 9 - barlap boljak usuly ulanýarys. 77 - obýektiň indi ýokdugyny barlaýarys. Garaşlylyk nukdaýnazaryndan nämäniň bardygyny göreliň:
<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>
Bularyň hemmesi şu gün meniň üçin))
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION