เมื่อเร็ว ๆ นี้เพื่อนร่วมงานของฉันถามฉันว่าฉันมี e-books เกี่ยวกับเทคโนโลยีหรือไม่ ฉันเปิดห้องสมุดขนาดเล็กบนคอมพิวเตอร์ของฉัน แต่อีเมลใหญ่เกินไปที่จะส่งเขาและ บริษัท ห้ามการแบ่งปันกับโฟลเดอร์ดังนั้นฉันใช้เวลาครึ่งวันเขียนโปรแกรมอัปโหลดไฟล์ขนาดเล็กและปรับใช้กับเครื่อง Linux ของฉัน
ให้ฟังก์ชั่น: 1. ไฟล์อัปโหลด 2. แสดงรายการไฟล์และดาวน์โหลด
ชิ้นส่วนที่อัปโหลดต้นฉบับน่าเกลียด ฉันเขียนโค้ด JS บางตัวเพื่อปรับให้เหมาะสม อินเทอร์เฟซสุดท้ายจะแสดงดังนี้:
ก่อนอื่นให้ผลลัพธ์และด้านล่างจะแสดงให้เห็นถึงวิธีการใช้งานพวกเขาทีละขั้นตอน
1. สร้างโครงการใหม่
สิ่งแรกคือการสร้างโครงการฤดูใบไม้ผลิใหม่ คุณสามารถเลือกที่จะเริ่มต้นโครงการบนเว็บไซต์หรือใช้ฟังก์ชั่น Spring Initialier ของ IDE และคุณสามารถสร้างโครงการใหม่ได้ ที่นี่ฉันสร้างโครงการใหม่จาก IDEA:
จากนั้นป้อนกลุ่มและสิ่งประดิษฐ์และคลิกต่อไปต่อไป:
ในเวลานี้อินเทอร์เฟซการเลือกโมดูลนี้จะปรากฏขึ้น คลิกตัวเลือกเว็บและตรวจสอบเว็บเพื่อพิสูจน์ว่านี่คือ WebApp จากนั้นคลิกเครื่องยนต์เทมเพลตเพื่อเลือกเอ็นจิ้นเทมเพลตส่วนหน้า เราเลือก thymleaf เจ้าหน้าที่ฤดูใบไม้ผลิ-บูทยังแนะนำให้ใช้เทมเพลตนี้แทน JSP
ขั้นตอนสุดท้ายจากนั้นรอให้โครงการเริ่มต้นสำเร็จ
2. การตั้งค่า pom
ก่อนอื่นให้ตรวจสอบว่าคุณต้องเพิ่มขึ้นในโครงการและโพสต์ไฟล์ POM ของฉันโดยตรง:
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <project xmlns = "http://maven.apache.org/pom/4.0.0" xmlns: xsi = "http://www.w3.org/2001/ XSI: schemalocation = "http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <moderversion> 4.0.0 <Sersion> 0.0.1-SNAPSHOT </เวอร์ชัน> <packaging> jar </packaging> <name> อัปโหลด </name> <scription> โครงการสาธิตสำหรับการบูตฤดูใบไม้ผลิ </คำอธิบาย> <parent> <roupid> org.springframework.boot </groupid> <ratifactid> ฤดูใบไม้ผลิ การค้นหาผู้ปกครองจากที่เก็บ-> </parent> <properties> <project.build.sourceencoding> utf-8 </project.build.sourceencoding> <project.raporting.outputencoding> UTF-8 </project.reporting.UutPutuCoding> <การพึ่งพา> <roupId> org.springframework.boot </groupId> <ratifactid> Spring-Boot-Starter </artifactid> </serpendency> <การพึ่งพาอาศัย> <roupid> org.springframework.boot </groupid> <ratifactid> <RoupID> org.springframework.boot </groupId> <ratifactid> Spring-Boot-Configuration-Processor </artifactid> <plorial> True </onftiveal> </predency> <Scope> ทดสอบ </cope> </predency> <!-https://mvnrepository.com/artifact/org.webjars/bootstrap-> <การพึ่งพา> <roupid> org.webjars </groupid> https://mvnrepository.com/artifact/org.webjars.bower/jquery -> <การพึ่งพา> <GroupId> org.webjars.bower </groupid> <ratifactid> jQuery </artifactid> <RoupID> org.springframework.boot </groupId> <ratifactid> Spring-Boot-Maven-Plugin </artifactid> </plugin>
คุณจะเห็นได้ว่า Spring-Boot-Starter-Thymeleaf มี WebApp และ Webjars สองตัวสุดท้ายรวม bootstrap และ jQuery และรหัสอื่น ๆ จะถูกใช้
ปลั๊กอิน maven boot สปริงล่าสุดจะถูกเพิ่มเมื่อระบบถูกสร้างขึ้นและมีประโยชน์ดังต่อไปนี้:
1. สามารถบรรจุขวดทั้งหมดภายใต้ ClassPath และสร้าง "über-jar" ที่ปฏิบัติการได้เพื่ออำนวยความสะดวกให้ผู้ใช้ถ่ายโอนบริการ
2. วิธีการค้นหาโมฆะแบบคงที่สาธารณะ () โดยอัตโนมัติและทำเครื่องหมายว่าเป็นคลาสปฏิบัติการได้
3. ตามเวอร์ชันสปริงบู๊ทจะมีคำอธิบายการพึ่งพาในตัว
3. อัปโหลดตัวควบคุมไฟล์
หากคุณเพิ่งใช้ SpringMVC เพื่ออัปโหลดไฟล์คุณจะต้องกำหนดค่าถั่วหลายตัวหรือกำหนดค่า <multipart-config> ใน web.xml แต่ด้วยความช่วยเหลือของการกำหนดค่าอัตโนมัติของ Spring-Boot คุณไม่ต้องทำอะไรเลย ในการเขียนคลาสคอนโทรลเลอร์โดยตรงเราสร้างแพ็คเกจคอนโทรลเลอร์ใหม่ภายใต้ SRC/Main/Java และสร้าง FilePloadController ใหม่:
แพ็คเกจ com.shuqing28.upload.controller; นำเข้า com.shuqing28.uploadfiles.pojo.linker; นำเข้า com.shuqing28.uploadfiles.exceptions.storagefilenotfoundexception; org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.core.io.resource; นำเข้า org.springframework.http.httpheaders; นำเข้า org.springframework.http. org.springframework.ui.model; นำเข้า org.springframework.web.bind.annotation.*; นำเข้า org.springframework.web.multipart.multipartfile; นำเข้า org.springframework. org.springframework.web.servlet.mvc.support.redirectattributes นำเข้า java.io.ioexception; นำเข้า java.util.list; นำเข้า java.util.stream.collectors; @controllerpublic @AutoWired Public FilePloadController (StorageService StorageService) {this.storageservice = StorageService; } @getMapping ("/") สตริงสาธารณะ listuploadedFiles (รุ่นโมเดล) พ่น IOException {รายการ <linker> linkers = Storageservice.loadall (). แผนที่ (เส้นทาง -> linker ใหม่ path.getFilename (). toString ()). build (). toString (), path.getFilename (). toString ())) .collect (collector.tolist ()); model.addattribute ("linkers", linkers); ส่งคืน "อัพโหลดฟอร์ม"; } @getMapping ("/files/{fileName:.+}") @ResponseBody การตอบสนองสาธารณะ <resource> ServeFile (@PathVariable String filename) {Resource File = StorageService.loadAsResource (ชื่อไฟล์); return responseEntity.ok (). ส่วนหัว (httpheaders.content_disposition, "ไฟล์แนบ; filename =/" " + file.getFileName () +" /"").body(file); } @PostMapping ("/") Public String HandleFileUpload (@RequestParam ("ไฟล์") ไฟล์ MultipArtFile, RedirectAtTributes RedirectAtTributes) {StorageService.store (ไฟล์); redirectattributes.addflashattribute ("ข้อความ", "คุณอัปโหลดสำเร็จ" + file.getoriginalfilename () + "!"); กลับ "เปลี่ยนเส้นทาง:/"; } @ExceptionHandler (StorageFilenotFoundException.class) ResponseEntity สาธารณะ <?> handlestorageFilenotfound (StorageFilenotFoundException exc) {return responseEntity.notfound (). สร้าง (); -คำอธิบายประกอบ @Controller จะถูกเพิ่มที่นิยามคลาสโดยพิสูจน์ว่านี่เป็นคอนโทรลเลอร์ แต่ละวิธีจะถูกเพิ่มด้วย @getMapping และ @postmapping ที่สอดคล้องกับการรับและโพสต์คำขอตามลำดับ
ก่อนอื่น @getMapping ("/"), method listuploadedfiles ตามชื่อหมายถึงแสดงรายการไฟล์ ที่นี่เราใช้ StorageService เพื่อสำรวจไฟล์ทั้งหมดในโฟลเดอร์และใช้เมธอดแผนที่เพื่อสังเคราะห์ลิงก์และรายการชื่อไฟล์โดยส่งคืนอาร์เรย์ของวัตถุ Linker วัตถุ linker เป็น pojo ง่าย ๆ ซึ่งมีเพียงสองส่วนต่อไปนี้:
สตริงส่วนตัว fileUrl; ชื่อไฟล์สตริงส่วนตัว;
วิธีนี้รวมถึงการใช้สตรีมใน Java8 หากคุณไม่เข้าใจคุณสามารถอ่านบทความนี้เกี่ยวกับคุณสมบัติ Java8 ในรายละเอียด (ii) สตรีม API
ถัดไปคือ @GetMapping("/files/{filename:.+}") ซึ่งเป็น ServeFile ซึ่งมีฟังก์ชั่นดาวน์โหลดไฟล์หรือใช้ StorageService และรหัส StorageService จะถูกโพสต์ในภายหลัง ในที่สุดใช้ ResponseEntity เพื่อส่งคืนไฟล์เป็นร่างกายไปยังบุคคลที่ร้องขอ
handlefileupload ของ @PostMapping("/") ใช้คำขอโพสต์เพื่ออัปโหลดไฟล์ พารามิเตอร์ @requestparam ("ไฟล์") แยกวัตถุไฟล์ในคำขอหน้าเว็บหรือใช้ StorageService เพื่อบันทึกวัตถุและในที่สุดก็ใช้การเปลี่ยนเส้นทางเพื่อรีเฟรชหน้าเว็บและให้ข้อความที่อัปโหลดสำเร็จ
4. การประมวลผลไฟล์
มีวิธีการหลายวิธีที่เรียกโดยคอนโทรลเลอร์ด้านบนโดย StorageService เรากำหนดอินเทอร์เฟซที่มีวิธีการต่อไปนี้:
แพ็คเกจ com.shuqing28.uploadfiles.service; นำเข้า org.springframework.core.io.resource; นำเข้า org.springframework.web.multipart.multipartfile; นำเข้า java.nio.file.path; Void Store (ไฟล์ MultipartFile); สตรีม <Path> loadall (); โหลดพา ธ (ชื่อไฟล์สตริง); Resource LoadAsResource (ชื่อไฟล์สตริง); เป็นโมฆะ deleteAll ();}
เนื่องจากฉันเพิ่งใช้ระบบไฟล์ในพื้นที่เพื่อประมวลผลการดาวน์โหลดไฟล์ระยะยาวฉันจึงมีคลาสการใช้งานต่อไปนี้:
แพ็คเกจ com.shuqing28.uploadfiles.service; นำเข้า com.shuqing28.uploadfiles.exceptions.storageException; นำเข้า com.shuqing28.uploadfiles.exceptions.storagefilenotfoundexception; org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.core.io.resource; นำเข้า org.springframework.core.io.urlresource; org.springframework.util.stringutils; นำเข้า org.springframework.web.multipart.multipartfile; นำเข้า java.io.ioexception; นำเข้า java.net.malformedurlexception; java.nio.file.Paths; นำเข้า java.nio.file.standardCopyOption; นำเข้า java.util.stream.stream; @ServicePublic คลาสไฟล์ FileSystorageservice ใช้ Storageservice @Autowired Public FilesSystorageService (คุณสมบัติ StorAgeProperties) {this.rootLocation = paths.get (properties.getLocation ()); } @Override โมฆะสาธารณะ init () {ลอง {files.createdirectories (rootlocation); } catch (ioexception e) {โยน storageException ใหม่ ("ไม่สามารถเริ่มต้นการจัดเก็บ", e); }} @Override void store (ไฟล์ multipartFile) {String filename = stringUtils.cleanPath (file.getoriginalfilename ()); ลอง {ถ้า (file.isempty ()) {โยน storageException ใหม่ ("ไม่สามารถจัดเก็บไฟล์ว่าง" + ชื่อไฟล์); } if (filename.contains (".. ")) {// นี่คือการตรวจสอบความปลอดภัยโยน storageException ใหม่ ("ไม่สามารถจัดเก็บไฟล์ที่มีเส้นทางสัมพัทธ์นอกไดเรกทอรีปัจจุบัน" + ชื่อไฟล์); } files.copy (file.getInputStream (), this.rootlocation.resolve (ชื่อไฟล์), StandardCopyOption.replace_existing); } catch (ioexception e) {โยน storageException ใหม่ ("ไม่สามารถจัดเก็บไฟล์" + ชื่อไฟล์, e); }} @Override สตรีมสาธารณะ <Ath> loadall () {ลอง {return files.walk (this.rootLocation, 1) .filter (path ->! path.equals (this.rootlocation)) .map (path-> this.rootlocation.relative (พา ธ )); } catch (ioexception e) {โยน storageException ใหม่ ("ไม่สามารถอ่านไฟล์ที่เก็บไว้", e); }} @Override Public Path Load (ชื่อไฟล์สตริง) {return rootlocation.resolve (ชื่อไฟล์); } @Override ทรัพยากรสาธารณะ LoadAsResource (ชื่อไฟล์สตริง) {ลอง {path file = load (ชื่อไฟล์); ทรัพยากรทรัพยากร = urlresource ใหม่ (file.touri ()); if (resource.exists () || resource.isreadable ()) {return resource; } else {โยน storagefilenotfoundexception ใหม่ ("ไม่สามารถอ่านไฟล์:" + ชื่อไฟล์); }} catch (malformedurlexception e) {โยน storagefilenotfoundexception ใหม่ ("ไม่สามารถอ่านไฟล์:" + filename, e); }} @Override โมฆะสาธารณะ deleteAll () {filesystemutils.deleterecursively (rootlocation.tofile ()); -คลาสนี้ยังใช้ NIO ของ Java และใช้วัตถุเส้นทางเพื่อกำหนดเส้นทางการบันทึกเริ่มต้นสำหรับตำแหน่งสำหรับไฟล์
มาดูวิธีการจัดเก็บก่อน ร้านค้ายอมรับวัตถุ MultipartFile เป็นพารามิเตอร์ เมื่อเทียบกับ JSP แบบดั้งเดิมมันเป็นเพียงการผ่านอาร์เรย์ไบนารีไบนารี MultipartFile มีวิธีการโทรที่สะดวกมากมายเพื่อให้เราสามารถรับข้อมูลต่าง ๆ เกี่ยวกับไฟล์ที่อัปโหลดได้:
อินเตอร์เฟสสาธารณะ MultipartFile ขยาย InputStreamSource {String getName (); สตริง getoriginalfilename (); String getContentType (); บูลีน isempty (); ได้รับนาน (); ไบต์ [] getBytes () พ่น IOException; InputStream getInputStream () พ่น IOException; เป็นโมฆะ transferto (ไฟล์ dest) พ่น IOException, unlilgalStateException;} รหัสใช้วิธีการคัดลอกไฟล์เพื่อคัดลอกสตรีมไฟล์ไปยังเส้นทางที่สอดคล้องกับตำแหน่ง แน่นอนเรายังสามารถใช้วิธีการ TRANSFERTO เพื่อบันทึกไฟล์ไฟล์ file.transferTo(this.rootLocation.resolve(filename).toFile());
วิธีการโหลดอลล์โหลดข้อมูลพา ธ ไฟล์ทั้งหมดในเส้นทางนี้ LoadAsResource โหลดไฟล์เป็นวัตถุทรัพยากรจากนั้นดูที่รหัสคอนโทรลเลอร์และในที่สุดก็รับวัตถุทรัพยากรเป็นตัวถังเพื่อกลับไปยังผู้ร้องขอ
5. เทมเพลตส่วนหน้า
ในที่สุดเทมเพลตส่วนหน้าจะถูกกำหนดและที่นี่เราจะยังคงดูรหัสก่อน:
<html xmlns: th = "http://www.thymeleaf.org"> <head> <title> แชร์ไฟล์ </title> </head> <body> <div th: ถ้า = "$ {ข้อความ}"> <h2 th: text = "$}"/> enctype = "multipart/form-data"> <!-ส่วนประกอบเริ่มต้น-> <input type = "file" name = "file" style = "การมองเห็น: hidden; ความสูง: 0"/> <div> <div name = "fichier1"> <อินพุต type = "text" -> <div> <button type = "ส่ง"> ส่ง </button> <button type = "Reset"> รีเซ็ต </button> </div> </form> </div> <div> <ul> <li th: แต่ละ linker: $ {linkers} "> <a th: href =" $ {linker.fileurl} th: text = "$ {linker.filename}"/> </li></ul> </div> <script src = "// ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.1.min.js"></script> src = "/webjars/bootstrap/3.3.5/js/bootstrap.min.js"> </script> <script type = "text/javascript" th: inline = "javascript"> ฟังก์ชั่น bs_input_file () {$ ("อินพุต- {var element = $ (". input-ghost"); element.hange (ฟังก์ชั่น () {element.next (องค์ประกอบ) .find ('อินพุต'). val ((element.val ()). แยก ('//') $ (นี่) .find ("button.btn-reset") คลิก (ฟังก์ชั่น () {element.val (null); $ (นี่). parents (". อินพุต-ไฟล์") ค้นหา (อินพุต '). val (');}; {$ (นี้) .parents ('. input-file'). prev (). คลิก (); } $ (function () {bs_input_file ();}); </script> <link rel = "stylesheet" href = "/webjars/bootstrap/3.3.5/css/bootstrap.min.css" rel = "ภายนอก nofollow"/> </body> </html>สิ่งสำคัญที่นี่คือเนื้อหาในแท็ก <form> <method form = "post" action = "/" enctype = "multipart/form-data"> Enctype ต้องเขียนเป็น multipart/form-data ใช้โพสต์เพื่ออัปโหลดไฟล์ การควบคุมการอัปโหลดดั้งเดิมนั้นน่าเกลียดดังนั้นฉันจึงสร้างข้อความ+อินพุตและวางไว้บนพื้นผิวและวางอินพุตไฟล์อัปโหลดที่มองไม่เห็นด้านล่าง คุณสามารถดูรหัสด้วยตัวเองดังนั้นฉันจะไม่พูดถึงเรื่องนี้ในบทความนี้
ที่นี่เรายังวางรายการเพื่อแสดงรายการไฟล์ ที่นี่เราได้รับวัตถุ Linkers ที่จัดทำโดยเซิร์ฟเวอร์ โดย Foreach อย่างต่อเนื่องเราสามารถรับองค์ประกอบสองอย่างใน FileUrl และชื่อไฟล์
ที่นี่ jQuery ถูกแทนที่ด้วย CDN ของ Microsoft และไม่สามารถแนะนำ webjars ได้ดังนั้นฉันไม่รู้ว่าทำไม
การตั้งค่าอื่น ๆ
ตั้งค่าขีด จำกัด ขนาดไฟล์อัปโหลดใน src/main/resources/application.properties
Spring.http.multipart.max-file-size = 128mbspring.http.multipart.max-request-size = 128mb
นอกจากนี้เส้นทางการบันทึกไฟล์เริ่มต้นยังถูกตั้งค่า:
แพ็คเกจ com.shuqing28.uploadfiles.config; นำเข้า org.springframework.boot.context.properties.configurationProperties; @configurationProperties ("Storage") StorageProperties สาธารณะ สตริงสาธารณะ getLocation () {ตำแหน่งส่งคืน; } โมฆะสาธารณะ setLocation (ตำแหน่งสตริง) {this.location = ตำแหน่ง; -หมายเหตุที่นี่เนื่องจากการตั้งค่า StorageProperties คุณต้องเพิ่มลงในคลาสแอปพลิเคชัน
@enableConfigurationProperties คำอธิบายประกอบ@springbootapplication@enableConfigurationProperties (StorageProperties.class) คลาสสาธารณะ uploadApplication {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {springapplication.run (uploadapplication.class -สรุป
ข้างต้นคือ Spring Boot + Thymeleaf ที่ตัวแก้ไขแนะนำให้คุณทราบฟังก์ชั่นการอัปโหลดและดาวน์โหลดไฟล์ ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับคุณทันเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!