<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
案例:圖書管理(SpringBoot+Thymeleaf+SpringData-JPA)
新增圖書:圖書基本資訊及封面圖片的上傳及入庫
圖書詳細:圖書基本資訊和封面圖片顯示
CREATE DATABASE wdzldb` USE `wdzldb`; DROP TABLE IF EXISTS `book`; CREATE TABLE `book` ( `bookid` int(11) NOT NULL AUTO_INCREMENT, `bookName` varchar(120) DEFAULT NULL, `price` float DEFAULT NULL, `pubDate` date DEFAULT NULL, `author` varchar(20) DEFAULT NULL, `version` int(11) DEFAULT '0', `state` int(11) DEFAULT NULL, `pic` varchar(50) DEFAULT NULL, PRIMARY KEY (`bookid`) ) ENGINE=InnoDB AUTO_INCREMENT=157 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `book` */ insert into `book`(`bookid`,`bookName`,`price`,`pubDate`,`author`,`version`,`state`,`pic`) values (22,'Java實戰開發3',34,'2021-07-28','王磊',1,1,NULL), (53,'Java實戰開發666',120,'2021-07-24','諸葛亮',0,1,NULL), (61,'Java實戰開發1',39,'2021-07-29','王磊',0,1,NULL), (62,'Java實戰開發1',39,'2021-07-29','王磊',0,0,NULL), (66,'Java實戰開發1',39,'2021-07-29','王磊',0,0,NULL), (67,'SpringCloud微服務實戰',45,'2021-08-11','王帆',0,0,NULL), (68,'SPringBoot整合JDBC',56,'2021-08-11','周瑜',0,1,NULL), (70,'SpringBoot入門與提高',78,'2021-08-11','曹操',0,1,NULL), (71,'Java實戰開發5',100,'2021-07-23','諸葛亮',0,0,NULL), (72,'Java虛擬機器器深入',23,'2021-08-11','趙紫陽',0,1,NULL), (73,'深入學習Java虛擬機器器',69,'2021-08-05','黃蓋',0,0,NULL), (74,'JSP開發技術',34,'2021-08-12','王超',0,1,NULL)
先搭建基本框架,完成業務層、DAO 層、pojo 等模組編寫,並偵錯通過 springdata 正常使用。
web 啟動器、thymeleaf 模板啟動器、springdata 啟動器及資料庫驅動等
<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>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
application.yml 資料來源的基本資訊設定、jpa 是否顯示 sql 及 下劃線等
spring: datasource: username: root password: root url: jdbc:mysql://127.0.0.1:3306/wdzldb?allowMultiQueries=true&useUnicode=true&allowPublicKeyRetrieval=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai driver-class-name: com.mysql.cj.jdbc.Driver jpa: show-sql: true hibernate: naming: physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
application.properties
下面多數是在使用阿里的初始化工具時,自動生成的
除了下面的上傳儲存的路徑是自定義的
# 應用名稱 spring.application.name=springboot_other # 應用服務 WEB 存取埠 server.port=8080 # THYMELEAF (ThymeleafAutoConfiguration) # 開啟模板快取(預設值: true ) spring.thymeleaf.cache=false # 檢查模板是否存在,然後再呈現 spring.thymeleaf.check-template=true # 檢查模板位置是否正確(預設值 :true ) spring.thymeleaf.check-template-location=true #Content-Type 的值(預設值: text/html ) spring.thymeleaf.content-type=text/html # 開啟 MVC Thymeleaf 檢視解析(預設值: true ) spring.thymeleaf.enabled=true # 模板編碼 spring.thymeleaf.encoding=UTF-8 # 要被排除在解析之外的檢視名稱列表,⽤逗號分隔 spring.thymeleaf.excluded-view-names= # 要運⽤於模板之上的模板模式。另⻅ StandardTemplate-ModeHandlers( 預設值: HTML5) spring.thymeleaf.mode=HTML # 在構建 URL 時新增到檢視名稱前的字首(預設值: classpath:/templates/ ) spring.thymeleaf.prefix=classpath:/templates/ # 在構建 URL 時新增到檢視名稱後的字尾(預設值: .html ) spring.thymeleaf.suffix=.html #上傳的絕對路徑 file.upload.path=d://save/images/ #絕對路徑下的相對路徑 file.upload.relativePath=/images/ #檔案上傳大小限制 spring.servlet.multipart.max-file-size=2048000
注意:日期和圖片處理
@Data @Entity(name = "book") //要求必須有@Id 也 @ApiModel(value = "圖書實體", description = "圖書中明細屬性") public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) //注意:預設的是序列,針對Oracle的 private Integer bookId; @ApiModelProperty(value = "圖書名") private String bookName; @ApiModelProperty(value = "圖書作者") private String author; private Float price; @Column(name = "pic") private String picpath; // 封面 @DateTimeFormat(pattern = "YYYY-MM-dd") private Date pubDate; //出版日期 }
dao 介面直接使用 springdata 提供的統一介面 JpaRepository ,其中已經包含了基本的操作。也可以按約定規則自己定義其他方法
注意:繼承介面時需要指定泛型
public interface IBookDao extends JpaRepository<Book, Integer> { List<Book> queryBooksByBookName(String bookName); List<Book> findBooksByPriceBetween(Float min, Float max); List<Book> findBooksByBookNameLike(String bookName); List<Book> findAllByPriceOrderByPrice(float price); @Query( "select bookId,bookName,price,author from Book where bookName like :bookname" ) Object[] queryBook(@Param("bookname") String bookName); //HQL 語句 select book from Book book where ... @Query("from Book where bookName like :bookname") List<Book> queryBooks(@Param("bookname") String bookName); }
介面和實現類
public interface IBookService { void add(Book book); void delete(Integer bookId); Book detail(Integer bookId); List<Book> queryAll(); void update(Book book); }
package com.wdzl.service.impl; import com.wdzl.dao.IBookDao; import com.wdzl.pojo.Book; import com.wdzl.service.IBookService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @Author: zhang * @Date:2022/8/12 * @Description: */ @Service public class BookService implements IBookService { @Autowired private IBookDao bookDao; @Override public void add(Book book) { System.out.println(book.getBookId()); bookDao.save(book); // 注意: 如果物件在資料庫中存在的,執行修改。 System.out.println(book.getBookId()); } @Override public void delete(Integer bookId) { bookDao.deleteById(bookId); } @Override public Book detail(Integer bookId) { return bookDao.findById(bookId).get(); } @Override public List<Book> queryAll() { return bookDao.findAll(); } @Override public void update(Book book) { //如果物件是存在時,就是修改操作,如果不存在則插入操作 bookDao.save(book); } }
到這裡,就可以使用單元測試來測試 springdata 是否能正常使用了。
頁面必須
1.method必須是post
2.enctype="multipart/form-data" 必須
3.<input type="file"/>必須
static 目錄 下的 add.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Title</title> </head> <body> <!-- 檔案上傳時:頁面必須 1.method必須是post 2.enctype="multipart/form-data" 必須 3.<input type="file"> 必須 --> <h2>新增圖書</h2> <form action="add" method="post" enctype="multipart/form-data"> <p>圖書名字:<input name="bookName" /></p> <p>圖書價格:<input name="price" /></p> <p>圖書作者:<input name="author" /></p> <p>出版日期:<input name="pubDate" type="date" /></p> <p>圖書封面:<input name="pic" type="file" /></p> <p><input type="submit" value="儲存" /></p> </form> </body> </html>
注意檔案上傳處理:單獨上傳、檔名重新命名、儲存路徑的設定等
package com.wdzl.controller; import com.wdzl.pojo.Book; import com.wdzl.service.IBookService; import com.wdzl.util.FileUtils; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; /** * @Author: zhang * @Date:2022/8/12 * @Description: * */ @Controller public class BookController { @Autowired private IBookService bookService; @Value("${file.upload.savepath}") private String savePath; //儲存檔案根目錄 @Value("${file.upload.relativePath}") private String relativePath; /** * 日期處理 * 檔案上傳 * @param book * @return */ @PostMapping("add") public String add(Book book, MultipartFile pic) { System.out.println("============add()========"); String oriName = pic.getOriginalFilename(); //原始檔案命名 //判斷目錄是否存在並建立 File rootDir = new File(savePath); if (rootDir.exists() == false) { rootDir.mkdirs(); } if (!pic.isEmpty()) { //檔名 String fileName = FileUtils.rename(oriName); File saveFile = new File(rootDir, fileName); //轉存到指定檔案中 try { pic.transferTo(saveFile); System.out.println(">>>>>>檔案儲存在:" + saveFile.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } // 檔案相對路徑 用來入庫和回顯 fileName = relativePath + fileName; book.setPicpath(fileName); } //入庫 bookService.add(book); return "redirect:list"; // /list } @GetMapping("list") public String list(ModelMap modelMap) { List<Book> list = bookService.queryAll(); modelMap.put("booklist", list); return "list"; ///templates/list.html } @GetMapping("detail") public String detail(Integer bookId, ModelMap modelMap) { Book book = bookService.detail(bookId); modelMap.put("book", book); return "detail"; } }
新增成功後,跳轉到列表頁面顯示,下面使用的 thymeleaf 遍歷顯示
注意:下面圖片路徑、連結等處理
templates 下的 list.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>圖書列表</title> <style type="text/css" rel="stylesheet"> div { margin: 30px; text-align: center; } </style> </head> <body> <a href="add.html">新增圖書</a> <hr /> <div> <table width="75%"> <thead> <tr bgcolor="#556b2f"> <th>序號</th> <th>書名</th> <th>作者</th> <th>價格</th> <th>出版日期</th> <th>操作</th> </tr> </thead> <tbody> <tr th:each="book,st:${booklist}" th:bgcolor="${st.even?'#aac':''}"> <td th:text="${st.count}"></td> <td> <a th:href="${'detail?bookId='+book.bookId}" th:text="${book.bookName}" ></a> </td> <td th:text="${book.author}"></td> <td th:text="${book.price}"></td> <td th:text="${#dates.format(book.pubDate,'yyyy年MM月dd日')}"></td> <td> <a th:href="${'del?bookId='+book.bookId}">刪除</a> </td> </tr> </tbody> </table> </div> </body> </html>
到此,可以通過前端的 add.html 來實現新增和上傳操作了。
注意:預設檔案上傳大小是 1M,大於 1M 的會 500 異常。
可以通過設定修改預設檔案大小限制:
#檔案上傳大小限制 spring.servlet.multipart.max-file-size=2048000
在專案發布執行中,不希望直接顯示 500 異常頁面時,可以設定全域性異常解析器來進行處理
例外處理在 springboot 中有多種方式,下面介紹兩種
位置:在啟動類同包及子包下定義類
@ControllerAdvice public class GlobalExceptionHander { @ExceptionHandler(Exception.class) public String doException(Exception ex) { // 不能使用model 無法傳參到頁面顯示 System.out.println(">>>>==異常了:" + ex.toString()); return "error"; // 轉發到 error.html 頁面 } }
上面的 @ControllerAdvice 註解中已經包含 @Component 註解,所以直接會被 spring 掃描加入容器中。
/** * @Author: zhang */ @Configuration public class ApplicationConfig { /** * 全域性異常設定 * 頁面可以通過 exception物件來獲取 */ @Bean public SimpleMappingExceptionResolver doException() { SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); Properties properties = new Properties(); properties.setProperty("java.lang.Exception", "error"); //對映異常型別和轉發的頁面對應關係 resolver.setExceptionMappings(properties); System.out.println("===========異常設定======"); return resolver; } }
上面是一個 @Configuration 標註的設定類。異常物件會被轉發到頁面。
在完成上面的檔案上傳和圖書資訊新增之後,跳轉到圖書列表頁面,可以通過圖書名連結開啟圖書詳細資訊。
但在顯示圖片靜態資源時,路徑問題導致圖片無法正常顯示。
下面來再來處理下檔案上傳和回顯下載或顯示問題
先來回顧上傳時對於圖片儲存路徑的設定
首先我們先在組態檔中自定義了兩個路徑:絕對路徑和相對路徑
#上傳的絕對路徑, 檔案儲存的真正的目錄位置 file.upload.path=d://save/images/ #絕對路徑下的相對路徑 用於前端請求呼叫的邏輯地址,預設是不能直接使用的 file.upload.relativePath=/images/
在控制器儲存圖片時,使用上面地址儲存圖片和入庫記錄
@PostMapping("add") //注意這裡 pic 需要單獨和頁面元素對應,實體類中只是不同名的字串用來存地址 public String add(Book book, @ApiParam(value = "圖片檔案", required = true)MultipartFile pic){ System.out.println(book+"===="+pic); String fileName = pic.getOriginalFilename(); //重新命名 fileName = FileUtils.rename(fileName); // 儲存到磁碟 File saveDir = new File(savePath); //====================這裡是真實儲存目錄 if(saveDir.exists()==false){ saveDir.mkdirs();//建立儲存圖片的目錄 } File saveFile = new File(saveDir,fileName); try { pic.transferTo(saveFile); System.out.println("圖片儲存在:"+saveFile.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } //儲存的相對路徑 String picPath = relativePath + fileName; //==========這裡邏輯目錄 虛擬的 System.out.println(">>>入庫路徑:"+picPath); book.setPicpath(picPath); //儲存到實體類 入庫 //入庫 bookService.add(book); return "redirect:list"; }
首先從上面程式碼中可以看到,儲存的磁碟的目錄和入庫的路徑是不同的,預設是不對應不能存取的。
頁面中使用的路徑為資料庫中的相對邏輯路徑
<img th:src="${book.picpath}" width="200" />
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>圖書明細</title> </head> <body> <div> <p> <img th:src="${book.picpath}" width="200" /> </p> <p>書名:<span th:text="${book.bookName}"></span></p> <p>作者:<span th:text="${book.author}"></span></p> <p>價格:<span th:text="${book.price}"></span></p> <p> 出版日期:<span th:text="${#dates.format(book.pubDate,'yyyy-MM-dd')}" ></span> </p> </div> </body> </html>
如果需要能正常的存取,則使用下面的設定進行對映
實現 WebMvcConfigurer 同時 標註 @Configuration
/** * @Author: zhang * @Date:2022/8/11 * @Description: */ @Configuration public class ApplicationConfig implements WebMvcConfigurer { @Value("${file.upload.path}") private String savePath; @Value("${file.upload.relativePath}") private String relativePath; /** * 資源路徑對映 * 注意:路徑前加 "file:/" * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { System.out.println(relativePath + "==============" + savePath); registry .addResourceHandler(relativePath + "/**") .addResourceLocations("file:/" + savePath); } }
通過上面的設定後,再去存取就可以正常顯示圖片了。
以上就是基於SpringBoot實現圖片上傳及圖片回顯的詳細內容,更多關於SpringBoot圖片上傳 回顯的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45