基于SpringBoot实现图片上传及图片回显
案例:图书管理(SpringBoot+Thymeleaf+SpringData-JPA)
添加图书:图书基本信息及封面图片的上传及入库
图书详细:图书基本信息和封面图片显示
- 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 正常使用。
pom.xml 依赖
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
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); }
Service
接口和实现类
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 中有多种方式,下面介绍两种
1. @ControllerAdvice + @ExceptionHandler
位置:在启动类同包及子包下定义类
@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 扫描加入容器中。
2. @Configuration+SimpleMappingExceptionResolver
/** * @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 标注的配置类。异常对象会被转发到页面。
图片回显
在完成上面的文件上传和图书信息添加之后,跳转到图书列表页面,可以通过图书名链接打开图书详细信息。
但在显示图片静态资源时,路径问题导致图片无法正常显示。
下面来再来处理下文件上传和回显下载或显示问题
1. 回顾保存方式
先来回顾上传时对于图片保存路径的设置
首先我们先在配置文件中自定义了两个路径:绝对路径和相对路径
#上传的绝对路径, 文件保存的真正的目录位置 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>
2. 配置资源映射
如果需要能正常的访问,则使用下面的配置进行映射
实现 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图片上传 回显的资料请关注猪先飞其它相关文章!
原文出处:https://blog.csdn.net/zp8126/article/details/126311855
相关文章
使用PHP+JavaScript将HTML页面转换为图片的实例分享
这篇文章主要介绍了使用PHP+JavaScript将HTML元素转换为图片的实例分享,文后结果的截图只能体现出替换的字体,也不能说将静态页面转为图片可以加快加载,只是这种做法比较interesting XD需要的朋友可以参考下...2016-04-19- 这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
- 今天小编在这里就来给各位Photoshop的这一款软件的使用者们来说说把古装美女图片转为细腻的工笔画效果的制作教程,各位想知道方法的使用者们,那么下面就快来跟着小编一...2016-09-14
- 这篇文章主要介绍了Python 图片转数组,二进制互转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题
这篇文章主要介绍了解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-28- php如何实现抓取网页图片,相较于手动的粘贴复制,使用小程序要方便快捷多了,喜欢编程的人总会喜欢制作一些简单有用的小软件,最近就参考了网上一个php抓取图片代码,封装了一个php远程抓取图片的类,测试了一下,效果还不错分享...2015-10-30
jquery左右滚动焦点图banner图片鼠标经过显示上下页按钮
jquery左右滚动焦点图banner图片鼠标经过显示上下页按钮...2013-10-13- 这篇文章主要为大家详细介绍了SpringBoot实现excel文件生成和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-09
- 下面小编就为大家带来一篇利用JS实现点击按钮后图片自动切换的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-10-25
- 本文章来人大家介绍一个php文件上传类的使用方法,期望此实例对各位php入门者会有不小帮助哦。 简介 Class.upload.php是用于管理上传文件的php文件上传类, 它可以帮...2016-11-25
- 又码了一个周末的代码,这次在做一些关于文件上传的东西。(PHP UPLOAD)小有收获项目是一个BT种子列表,用户有权限上传自己的种子,然后配合BT TRACK服务器把种子的信息写出来...2016-11-25
- Photoshop的这一款软件小编相信很多的人都已经是使用过了吧,那么今天小编在这里就给大家带来了用Photoshop软件制作枪战电影海报的教程,想知道制作步骤的玩家们,那么下面...2016-09-14
- 这篇文章主要为大家详细介绍了js实现上传图片及时预览的相关资料,具有一定的参考价值,感兴趣的朋友可以参考一下...2016-05-09
- 本文实例讲述了jQuery实现文件上传进度条效果的代码。分享给大家供大家参考。具体如下: 运行效果截图如下:具体代码如下:<!DOCTYPE html><html><head><meta charset="utf-8"><title>upload</title><link rel="stylesheet...2015-11-24
- 这篇文章主要介绍了详解springBoot启动时找不到或无法加载主类解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16
- 本篇文章主要说明的是与php文件上传的相关配置的知识点。PHP文件上传功能配置主要涉及php.ini配置文件中的upload_tmp_dir、upload_max_filesize、post_max_size等选项,下面一一说明。打开php.ini配置文件找到File Upl...2015-10-21
- EXCEL数据上传到SQL SERVER中的方法需要注意到三点!注意点一:要把EXCEL数据上传到SQL SERVER中必须提前把EXCEL传到服务器上.做法: 在ASP.NET环境中,添加一个FileUpload上传控件后台代码的E.X: 复制代码 代码如下: if...2013-09-23
- 这篇文章主要介绍了SpringBoot集成Redis实现消息队列的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
- 图片剪裁是常用的方法,那么如何通过4坐标剪裁图片,本文就详细的来介绍一下,感兴趣的小伙伴们可以参考一下...2021-06-04
- 这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17