หลังจากโดนมรสุมงานหนักมาตั้งแต่ต้นปีครับ กว่าจะได้กลับบ้านที่ก็ปาไป 3 ทุ่มกว่าๆ ถึง 4 ทุ่มและ เริ่มกลับมาทำ Thesis สักทีครับ สำหรับโจทย์ที่ผมเอามาเขียน Blog ครั้งนี้เป็นการ Upload File จากนั้น Save ที่ไฟล์ที่ Server ครับ พร้อมกับบันทึกข้อมูลที่ป้อนเข้ามาจาก User ครับ
เตรียมตัว
- Tools พร้อม Code พร้อมครับ สำหรับผมใช้ Code ที่ตั้งโครงจาก Blog ก่อนๆมาพัฒนาต่อครับ
Just Coding ครับ
- กำหนด Dependency ที่เกี่ยวข้องกันก่อนในไฟล์ pom.xml ครับ
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>nz.net.ultraq.thymeleaf</groupId> <artifactId>thymeleaf-layout-dialect</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
- มากำหนด application.properties ครับ
#เปิด Option การใช้ Multipart spring.http.multipart.enabled=true #กำหนด Part ที่ Upload File bpmn.upload.path = D:\\BPMN\\99Web\\WuMuBPMN\\src\\main\\resources\\static\\BPMNUpload #กำหนดรูปแบบไฟล์ที่สามารถ Upload ได้ bpmn.upload.extensions=bpmn
- กำหนด Entity ครับ
@Entity
public class testItem{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int testItemId;
//บอก Path ที่เก็บไฟล์ BPMN
private String testItemPath;
private String testItemName;
@Transient
private MultipartFile BPMNFile;
//พวก getter และ setter ผมขอละไว้นะครับ
}สังเกตุดีๆ ผมมี Property ที่เกี่ยวกับ Multipart ชื่อ BPMNFile ครับ โดย Property นี้ ผมกำหนดเป็น @Transient ครับ ซึ่งเป็นตัวที่บอก Hibernate ว่าไม่ต้องสร้าง Column นี้ลงที่ฐานข้อมูลครับ
- สร้าง View ที่เกี่ยวข้องครับ - อันนี้ผมใช้ Thymeleaf Layout ครับ (สามารถศึกษาเพิ่มเติมได้จาก Blog ผมครับ อิอิ) แต่ผมใน Blog นี้ผมใส่เฉพาะ View ครับ
<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layouts/mainLayout">
<head>
<title>Layout</title>
</head>
<body>
<div layout:fragment="content">
<h2>Test Item Detail</h2>
<div>
<form class="form-horizontal" th:object="${testitem}" th:action="@{/testitem}" method="post" enctype="multipart/form-data">
<!-- <input type="hidden" th:field="*{testitemid}"/> -->
<div class="form-group">
<label class="col-sm-2 control-label">test item name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{testItemName}"/>
<label th:if="${#fields.hasErrors('testItemName')}" th:class="'error'">test Item Name Error</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">test item file:</label>
<div class="col-sm-10">
<input type="file" class="form-control" th:field="*{BPMNFile}"/>
<label th:if="${#fields.hasErrors('testItemPath')}" th:class="'error'">test Item Path Error</label>
</div>
<label class="col-sm-2 control-label">test item path:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{testItemPath}" readonly = true/>
<label th:if="${#fields.hasErrors('testItemPath')}" th:class="'error'">test Item Path Error</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</form>
</div>
</div>
</body>
</html>- สังเกตุในส่วนของ <input type="file" class="form-control" th:field="*{BPMNFile}"/> ครับ ในส่วนของ th:field="*{BPMNFile}" ครับ ตรง BPMNFile จะสัมพันธ์กับในส่วนของ Entity ครับ ^__^

- สร้าง Controller กันครับ มีครบครันสำหรับ CRUD Operation ไปดู Code ได้เลยครับ
package com.cu.thesis.WuMuBPMN.controllers.manageTest;
//ส่วนขอการ Import เชื่อใจใน Editor ครับ
@Controller
public class testItemController
{
//ดึงค่ามาจาก application.properties
@Value("${bpmn.upload.path}")
private String uploadPath;
@Value("${bpmn.upload.extensions}")
private String bpmnExtension;
@Autowired
private testItemService testItemServiceI;
/*
* ดึงข้อมูล TEst Case ทั้งหมด
*/
@RequestMapping(value = "testitems", method = RequestMethod.GET)
public String listTestItem(Model model)
{
model.addAttribute("testitems", testItemServiceI.listAll());
System.out.println("Returning testitems:");
return "manageTest/testItemList";
}
/**
* ดูข้อมูล Test Item
*/
@RequestMapping(value = "testitem/{id}")
public String viewTestItem(@PathVariable Integer id, Model model)
{
model.addAttribute("testitem", testItemServiceI.getById(id));
return "manageTest/viewTestItem";
}
/**
* Edit Entry สำหรับ Edit
*/
@RequestMapping(value = "testitem/edit/{id}")
public String editPerson(@PathVariable Integer id, Model model) {
model.addAttribute("testitem", testItemServiceI.getById(id));
return "manageTest/editTestItem.html";
}
/**
* new Entity สำหรับ New
*/
@RequestMapping(value = "testitem/new")
public String newTestItem(Model model)
{
model.addAttribute("testitem", new testItem());
return "manageTest/editTestItem.html";
}
/**
* บันทึกข้อมูลลง DB
*/
@RequestMapping(value ="testitem", method = RequestMethod.POST)
public String saveTestItem(@Valid testItem testItemEntry
, BindingResult result)
{
//จัดการ File
String FilePath;
try {
if(result.hasErrors()) {
return "manageTest/editTestItem.html";
}
FilePath = SaveBPMNFile(testItemEntry.getBPMNFile(), uploadPath);
testItemEntry.setTestItemPath(FilePath);
testItemServiceI.save(testItemEntry);
}
catch (IOException e) {
e.printStackTrace();
}
catch (FileUploadException e)
{
e.printStackTrace();
}
return "redirect:/testitems";
}
protected String SaveBPMNFile(MultipartFile file, String uploadDirectory) throws IOException, FileUploadException
{
String fileName = file.getOriginalFilename();
CheckValidFileExtension(file);
Path path = Paths.get(uploadDirectory, fileName);
Files.copy(file.getInputStream(), path);
return uploadDirectory +"/"+ fileName;
}
protected void CheckValidFileExtension(MultipartFile file) throws FileUploadException
{
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (!extension.equals(bpmnExtension))
{
throw new FileUploadException("Not valid BPMN Extension");
}
}
@RequestMapping(value ="testitem/delete/{id}")
public String deleteTestItem(@PathVariable Integer id) throws IOException
{
//ลบแล้ว ต้องเอาออกให้เกลี้ยงนะ
testItem testItemEntry = testItemServiceI.getById(id);
Files.deleteIfExists(Paths.get(testItemEntry.getTestItemPath()));
testItemServiceI.delete(id);
//กลับไปที่หน้าจอ List
return "redirect:/testitems";
}
}- ส่วน Service / DAO ใช้จาก CRUDRepository ตามปกติครับ ผมเลยไม่ใส่ Code นะครับ
หน้าตาของระบบ (ผมไม่มีหัวการออกแบบเลยครับ 555)
- หน้า List

- ตอน Edit ครับ

ปัญหาที่พบหละ ?
- ปัญหา Exception: MultipartException: Current request is not a multipart request
แก้ไขโดย - ตรวจสอบที่ View ในส่วนของ Form ว่าลืมใส่ enctype="multipart/form-data" หรือป่าว - ปัญหา Required request part 'file' is not present
แก้ไขโดย - ตรวจสอบที่ View ว่ามีการผูก Mulitipart Element อย่าง เช่น File Upload หรือ <input type="file" class="form-control" th:field="*{BPMNFile}"/> ครับ ยังไม่ได้ผูกกับ Model (Entity) แต่ Method ใน Controller ครับ มัน Require ตัว Multipart ครับ ถ้าใน Thymeleaf เป็นส่วน th:field="*{BPMNFile}" ครับ
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.



