【瑞吉外卖】day06:文件上传下载、菜品新增、菜品分页查询、菜品修改(一)

简介: 文件上传下载、菜品新增、菜品分页查询、菜品修改

1. 文件上传下载


1.1 上传介绍


1.1.1 概述


文件上传,也称为upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。

image.png

表单属性 取值 说明
method post 必须选择post方式提交
enctype multipart/form-data 采用multipart格式上传文件
type file 使用input的file控件上传

1.1.2 前端介绍


1). 简单html页面表单

1.<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#117700"><</span><span style="color:#117700">form</span> <span style="color:#0000cc">method</span>=<span style="color:#aa1111">"post"</span> <span style="color:#0000cc">action</span>=<span style="color:#aa1111">"/common/upload"</span> <span style="color:#0000cc">enctype</span>=<span style="color:#aa1111">"multipart/form-data"</span><span style="color:#117700">></span>
    <span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">name</span>=<span style="color:#aa1111">"myFile"</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"file"</span>  <span style="color:#117700">/></span>
    <span style="color:#117700"><</span><span style="color:#117700">input</span> <span style="color:#0000cc">type</span>=<span style="color:#aa1111">"submit"</span> <span style="color:#0000cc">value</span>=<span style="color:#aa1111">"提交"</span> <span style="color:#117700">/></span> 
<span style="color:#117700"></</span><span style="color:#117700">form</span><span style="color:#117700">></span></span></span>

2). ElementUI中提供的upload上传组件

目前一些前端组件库也提供了相应的上传组件,但是底层原理还是基于form表单的文件上传。

image.png

1.1.3 服务端介绍


服务端要接收客户端页面上传的文件,通常都会使用Apache的两个组件:

  • commons-fileupload
  • commons-io

而Spring框架在spring-web包中对文件上传进行了封装,大大简化了服务端代码,我们只需要在Controller的方法中声明一个MultipartFile类型的参数即可接收上传的文件,例如:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">/**</span>
 <span style="color:#aa5500">* 文件上传</span>
 <span style="color:#aa5500">* @param file</span>
 <span style="color:#aa5500">* @return</span>
 <span style="color:#aa5500">*/</span>
<span style="color:#555555">@PostMapping</span>(<span style="color:#aa1111">"/upload"</span>)
<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#008855">String</span><span style="color:#981a1a">></span> <span style="color:#0000ff">upload</span>(<span style="color:#000000">MultipartFile</span> <span style="color:#000000">file</span>){
    <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">file</span>);
    <span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">fileName</span>);
}</span></span>

1.2 下载介绍


文件下载,也称为download,是指将文件从服务器传输到本地计算机的过程。通过浏览器进行文件下载,通常有两种表现形式:

1). 以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录

image.png

2). 直接在浏览器中打开

而我们在今天所需要实现的菜品展示,表现形式为在浏览器中直接打开。

image.png

通过浏览器进行文件下载,本质上就是服务端将文件以流的形式写回浏览器的过程。

1.3 上传代码实现


1.3.1 前端代码


文件上传,我们作为服务端工程师,主要关注服务端代码实现。对于前端页面,可以使用ElementUI提供的上传组件。可以直接使用资料中提供的上传页面,位置:资料/文件上传下载页面/upload.html,将其拷贝到项目的目录(resources/backend/page/demo)下,启动项目,访问上传页面。

http://localhost:8080/backend/page/demo/upload.html

image.png

在上述的浏览器抓取的网络请求中,上传文件的调用url,在哪里配置的呢,这个时候,我们需要去看一下前端上传组件。

image.png

虽然上述是ElementUI封装的代码,但是实际上最终还通过file域上传文件,如果未指定上传文件的参数名,默认为file。

image.png

1.3.2 服务端实现


1). application.yml

需要在application.yml中定义文件存储路径

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">reggie</span><span style="color:#555555">:</span>
<span style="color:#221199">  path</span><span style="color:#555555">: </span>D<span style="color:#555555">:</span>\img\</span></span>

2). CommonController

编写文件上传的方法, 通过MultipartFile类型的参数即可接收上传的文件, 方法形参的名称需要与页面的file域的name属性一致。

所在包: com.itheima.reggie.controller

上传逻辑:

1). 获取文件的原始文件名, 通过原始文件名获取文件后缀

2). 通过UUID重新声明文件名, 文件名称重复造成文件覆盖

3). 创建文件存放目录

4). 将上传的临时文件转存到指定位置

代码实现:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">common</span>.<span style="color:#000000">R</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">extern</span>.<span style="color:#000000">slf4j</span>.<span style="color:#000000">Slf4j</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">beans</span>.<span style="color:#000000">factory</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Value</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#981a1a">*</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">multipart</span>.<span style="color:#000000">MultipartFile</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">File</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">UUID</span>;
<span style="color:#aa5500">/**</span>
 <span style="color:#aa5500">* 文件上传和下载</span>
 <span style="color:#aa5500">*/</span>
<span style="color:#555555">@RestController</span>
<span style="color:#555555">@RequestMapping</span>(<span style="color:#aa1111">"/common"</span>)
<span style="color:#555555">@Slf4j</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">CommonController</span> {
    <span style="color:#555555">@Value</span>(<span style="color:#aa1111">"${reggie.path}"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">basePath</span>;
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* 文件上传</span>
     <span style="color:#aa5500">* @param file</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@PostMapping</span>(<span style="color:#aa1111">"/upload"</span>)
    <span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#008855">String</span><span style="color:#981a1a">></span> <span style="color:#000000">upload</span>(<span style="color:#000000">MultipartFile</span> <span style="color:#000000">file</span>){
        <span style="color:#aa5500">//file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除</span>
        <span style="color:#000000">log</span>.<span style="color:#000000">info</span>(<span style="color:#000000">file</span>.<span style="color:#000000">toString</span>());
        <span style="color:#aa5500">//原始文件名</span>
        <span style="color:#008855">String</span> <span style="color:#000000">originalFilename</span> <span style="color:#981a1a">=</span> <span style="color:#000000">file</span>.<span style="color:#000000">getOriginalFilename</span>();<span style="color:#aa5500">//abc.jpg</span>
        <span style="color:#008855">String</span> <span style="color:#000000">suffix</span> <span style="color:#981a1a">=</span> <span style="color:#000000">originalFilename</span>.<span style="color:#000000">substring</span>(<span style="color:#000000">originalFilename</span>.<span style="color:#000000">lastIndexOf</span>(<span style="color:#aa1111">"."</span>));
        <span style="color:#aa5500">//使用UUID重新生成文件名,防止文件名称重复造成文件覆盖</span>
        <span style="color:#008855">String</span> <span style="color:#000000">fileName</span> <span style="color:#981a1a">=</span> <span style="color:#000000">UUID</span>.<span style="color:#000000">randomUUID</span>().<span style="color:#000000">toString</span>() <span style="color:#981a1a">+</span> <span style="color:#000000">suffix</span>;<span style="color:#aa5500">//dfsdfdfd.jpg</span>
        <span style="color:#aa5500">//创建一个目录对象</span>
        <span style="color:#000000">File</span> <span style="color:#000000">dir</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">File</span>(<span style="color:#000000">basePath</span>);
        <span style="color:#aa5500">//判断当前目录是否存在</span>
        <span style="color:#770088">if</span>(<span style="color:#981a1a">!</span><span style="color:#000000">dir</span>.<span style="color:#000000">exists</span>()){
            <span style="color:#aa5500">//目录不存在,需要创建</span>
            <span style="color:#000000">dir</span>.<span style="color:#000000">mkdirs</span>();
        }
        <span style="color:#770088">try</span> {
            <span style="color:#aa5500">//将临时文件转存到指定位置</span>
            <span style="color:#000000">file</span>.<span style="color:#000000">transferTo</span>(<span style="color:#770088">new</span> <span style="color:#000000">File</span>(<span style="color:#000000">basePath</span> <span style="color:#981a1a">+</span> <span style="color:#000000">fileName</span>));
        } <span style="color:#770088">catch</span> (<span style="color:#000000">IOException</span> <span style="color:#000000">e</span>) {
            <span style="color:#000000">e</span>.<span style="color:#000000">printStackTrace</span>();
        }
        <span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">fileName</span>);
    }
}    </span></span>

1.3.3 测试


代码编写完成之后,我们重新启动项目,访问上传页面 http://localhost:8080/backend/page/demo/upload.html,然后点击上传图片,选图片上传时,会发现图片并不能正常的上传,而且在浏览器中可以抓取到响应的数据,从图中我们可以判断出需要登录才可以操作。

image.png

而这样的话,就要求我们在测试时,每一次都需要先登录,登录完成后在进行图片上传的测试,为了简化我们的测试,我们可以在 LoginCheckFilter 的doFilter方法中,在不需要处理的请求路径的数组中再加入请求路径 /common/** , 如下:

image.png

然后,我们在测试文件的上传功能时,就不需要登录就可以操作了。

我们在测试文件上传时,可以通过debug的形式来跟踪上传的整个过程,验证一下临时文件是否存在,以及上传完成之后,临时文件是否会自动删除。

image.png

image.png

image.png

1.4 下载代码实现


1.4.1 前端代码


文件下载,前端页面可以使用标签展示下载的图片。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#117700"><</span><span style="color:#117700">img</span> <span style="color:#0000cc">v-if</span>=<span style="color:#aa1111">"imageUrl"</span> <span style="color:#0000cc">:src</span>=<span style="color:#aa1111">"imageUrl"</span> <span style="color:#0000cc">class</span>=<span style="color:#aa1111">"avatar"</span><span style="color:#117700">></</span><span style="color:#117700">img</span><span style="color:#117700">></span></span></span>

image.png

在文件上传成功后,在 handleAvatarSuccess 方法中获取文件上传成功之后返回的数据(文件名),然后调用 /common/download?name=xxx 进行文件的下载。在这里,我们想让上传的照片能够在页面展示出来,所以我们就需要在服务端将文件以流的形式写回浏览器。

1.4.2 服务端代码


在 CommonController 中定义方法download,并接收页面传递的参数name,然后读取图片文件的数据,然后以流的形式写回浏览器。

具体逻辑如下:

1). 定义输入流,通过输入流读取文件内容

2). 通过response对象,获取到输出流

3). 通过response对象设置响应数据格式(image/jpeg)

4). 通过输入流读取文件数据,然后通过上述的输出流写回浏览器

5). 关闭资源

代码实现:

1.<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">/**</span>
 <span style="color:#aa5500">* 文件下载</span>
 <span style="color:#aa5500">* @param name</span>
 <span style="color:#aa5500">* @param response</span>
 <span style="color:#aa5500">*/</span>
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/download"</span>)
<span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#0000ff">download</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>, <span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span>){
    <span style="color:#770088">try</span> {
        <span style="color:#aa5500">//输入流,通过输入流读取文件内容</span>
        <span style="color:#000000">FileInputStream</span> <span style="color:#000000">fileInputStream</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">FileInputStream</span>(<span style="color:#770088">new</span> <span style="color:#000000">File</span>(<span style="color:#000000">basePath</span> <span style="color:#981a1a">+</span> <span style="color:#000000">name</span>));
        <span style="color:#aa5500">//输出流,通过输出流将文件写回浏览器</span>
        <span style="color:#000000">ServletOutputStream</span> <span style="color:#000000">outputStream</span> <span style="color:#981a1a">=</span> <span style="color:#000000">response</span>.<span style="color:#000000">getOutputStream</span>();
        <span style="color:#000000">response</span>.<span style="color:#000000">setContentType</span>(<span style="color:#aa1111">"image/jpeg"</span>);
        <span style="color:#008855">int</span> <span style="color:#000000">len</span> <span style="color:#981a1a">=</span> <span style="color:#116644">0</span>;
        <span style="color:#008855">byte</span>[] <span style="color:#000000">bytes</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#008855">byte</span>[<span style="color:#116644">1024</span>];
        <span style="color:#770088">while</span> ((<span style="color:#000000">len</span> <span style="color:#981a1a">=</span> <span style="color:#000000">fileInputStream</span>.<span style="color:#000000">read</span>(<span style="color:#000000">bytes</span>)) <span style="color:#981a1a">!=</span> <span style="color:#981a1a">-</span><span style="color:#116644">1</span>){
            <span style="color:#000000">outputStream</span>.<span style="color:#000000">write</span>(<span style="color:#000000">bytes</span>,<span style="color:#116644">0</span>,<span style="color:#000000">len</span>);
            <span style="color:#000000">outputStream</span>.<span style="color:#000000">flush</span>();
        }
        <span style="color:#aa5500">//关闭资源</span>
        <span style="color:#000000">outputStream</span>.<span style="color:#000000">close</span>();
        <span style="color:#000000">fileInputStream</span>.<span style="color:#000000">close</span>();
    } <span style="color:#770088">catch</span> (<span style="color:#000000">Exception</span> <span style="color:#000000">e</span>) {
        <span style="color:#000000">e</span>.<span style="color:#000000">printStackTrace</span>();
    }
}</span></span>



相关文章
|
小程序
【易售小程序项目】悬浮按钮+出售闲置商品+商品分类选择【后端基于若依管理系统开发】
【易售小程序项目】悬浮按钮+出售闲置商品+商品分类选择【后端基于若依管理系统开发】
60 0
|
7月前
|
Java
Java实现菜品上架与展示
该代码示例展示了如何在Java中实现菜品的上架和展示功能。`Food`类包含菜品的名称、价格和描述属性。`FoodOpertor`类管理菜品的ArrayList,提供添加菜品和浏览菜品的方法,用户通过命令行选择操作。`start()`方法循环显示菜单供用户选择,直到选择退出。`ArryListCase1`是主类,用于运行程序。实现结果包括菜品的上架和展示界面。
78 1
|
7月前
|
SQL 测试技术
实战SSM_O2O商铺_32【商品】商品编辑之Dao层的实现
实战SSM_O2O商铺_32【商品】商品编辑之Dao层的实现
66 0
|
数据库
点餐系统新增excel菜品数据批量导入功能
点餐系统新增excel菜品数据批量导入功能
199 0
|
前端开发 测试技术 应用服务中间件
实战SSM_O2O商铺_34【商品】商品编辑之Controller层的实现
实战SSM_O2O商铺_34【商品】商品编辑之Controller层的实现
78 0
|
前端开发 应用服务中间件
实战SSM_O2O商铺_35【商品】商品编辑之View层的实现
实战SSM_O2O商铺_35【商品】商品编辑之View层的实现
75 0
|
监控 前端开发 Java
基于Springboot外卖系统20:前端菜品展示+菜品数量查询
左侧的分类菜单,和右侧的菜品信息都可以看到,后续只需要将购物车列表的数据改成调用服务端接口查询即可。
142 0
|
前端开发 API
谷粒商城--显示销售属性详情
谷粒商城--显示销售属性详情
168 0
|
JSON 监控 前端开发
基于Springboot外卖系统11:菜品新增类别+类别信息分页查询
后台系统中可以管理分类信息,分类包括两种类型,分别是 菜品分类 和 套餐分类 。当我们在后台系统中添加菜品时需要选择一个菜品分类,在后台系统中添加一个套餐时需要选择一个套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐。
192 0
|
前端开发 Java 数据库
基于Springboot外卖系统12:删除菜品套餐类别+修改套餐类别信息
在分类管理列表页面,可以对某个分类进行删除操作。需要注意的是当分类关联了菜品或者套餐时,此分类不允许删除。
123 0

热门文章

最新文章