1. 商品修改页面绘制
1.1 编辑页面HTML
//1. 定义页面html
<!-- 定义商品修改的对话框 -->
<!-- 定义商品修改的对话框 -->
<el-dialog title="商品修改" :visible.sync="updateDialogVisible" width="60%">
<!-- 准备修改的表单-->
<el-form :model="updateItem" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="标题信息" prop="title">
<el-input v-model="updateItem.title"></el-input>
</el-form-item>
<el-form-item label="卖点信息" prop="sellPoint">
<el-input v-model="updateItem.sellPoint"></el-input>
</el-form-item>
<el-form-item label="价格信息" prop="price">
<el-input v-model="updateItem.price"></el-input>
</el-form-item>
<el-form-item label="数量信息" prop="num">
<el-input v-model="updateItem.num"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="updateDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
//2. 定义页面JS
updateDialogVisible: false,
updateItem: {
},
//准备一个校验规则
rules: {
title: [
{
required: true, message: '请输入商品标题信息', trigger: 'blur' },
{
min: 3, max: 50, message: '长度在 3 到 50 个字符', trigger: 'blur' }
],
sellPoint: [
{
required: true, message: '请输入商品卖点信息', trigger: 'blur' },
{
min: 3, max: 50, message: '长度在 3 到 50 个字符', trigger: 'blur' }
],
price: [
{
required: true, message: '请输入商品价格信息', trigger: 'blur' },
{
min: 3, max: 50, message: '长度在 3 到 50 个字符', trigger: 'blur' }
],
num: [
{
required: true, message: '请输入商品数量信息', trigger: 'blur' },
{
min: 3, max: 50, message: '长度在 3 到 50 个字符', trigger: 'blur' }
],
}
//定义JS按钮
updateItemBtn(item){
console.log("扩展案例,自己实现 只需要修改 标题/卖点/价格/数量")
this.updateDialogVisible = true
this.updateItem = item
this.updateItem.price = (this.updateItem.price / 100).toFixed(2)
}
2. 实现商品图片上传
2.1 编辑页面
2.1.1 官网说明
//1. 官网图片JS说明
<!-- 图片上传的JS
1. action: 代表图片上传的地址url
2. file-list: 图片列表数据的集合[{
name:"xx",url:"xxx"},{
}]
3. 钩子函数: 满足某些条件时触发.
4. on-preview 当点击已上传列表的信息时触发
5. on-remove 当移除列表中的图片时触发
-->
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList"
list-type="picture">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
2. 页面JS补充知识
handlePreview(){
console.log("触发查看函数!!!!")
},
handleRemove(){
console.log("移除时触发!!!!")
}
2.1.2 图片上传项目说明
<!--
一.文件上传组件说明
1.action: 上传图片地址 http://localhost:8091/xxx/xxx
2.on-preview 点击图片时触发
3.on-remove 移除图片时触发
4.on-success 图片上传成功时触发
5.multiple 可以支持多张图片上传
6.drag 是否允许拖拽
二.请求类型: 一般上传字节信息时,首选post请求
三.上传文件key 说明: 文件上传时的key=file.
后端接收数据时采用file接收.
-->
<el-upload class="upload-demo" :action="uploadUrl" :on-preview="handlePreview" :on-remove="handleRemove"
:on-success="handleSuccess" list-type="picture" multiple drag>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
//定义文件上传路径地址
uploadUrl: "http://localhost:8091/file/upload",
2.1.3 图片上传接口文档说明
- 请求路径: http://localhost:8091/file/upload
- 请求类型: post
- 请求参数:
参数名称 | 参数说明 | 备注 |
---|---|---|
file | 文件上传的参数名称 | file中携带的是二进制信息 |
- 返回值结果:
参数名称 | 参数说明 | 备注 |
---|---|---|
status | 状态信息 | 200表示服务器请求成功 |
msg | 服务器返回的提示信息 | 可以为null |
data | 服务器返回的业务数据 | 返回ImageVO对象 |
- ImageVO对象说明
参数名称 | 参数类型 | 参数说明 | 备注 |
---|---|---|---|
virtualPath | String | 图片实际路径 不包含磁盘信息 | 例如: 2021/11/11/a.jpg 不需要写磁盘地址 |
urlPath | String | 图片url访问地址 | http://image.jt.com/2021/11/11/a.jpg 需要指定域名地址 |
fileName | String | 文件上传后的文件名称 | UUID.type |
2.1.4 编辑ImageVO
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {
private String virtualPath; //图片虚拟路径 动态的路径
private String urlPath; //图片回显的URL地址
private String fileName; //文件上传后的文件名称
}
2.1.5 编辑ItemController
@RestController
@CrossOrigin
@RequestMapping("/file")
public class FileController {
/**
* 业务说明: 实现图片上传
* URL: http://localhost:8091/file/upload
* 类型: post
* 参数: file 字节信息
* 返回值: SysResult.success()
* 扩展:
* 一般情况下:
* 一般前端向后端服务器发送字节信息.由外到内实现数据传输.
* 采用输入流信息. InputStream file
* 使用字节流的弊端: 1.必须手动关闭, 2.代码操作繁琐
* 底层代码的实现.
* SpringMVC高级API MultipartFile 专门处理IO流操作
* 文件上传步骤:
* 1.获取文件名称
* 2.准备文件上传的目录
* 3.判断目录是否存在 存在目录: 实现上传 没有目录:创建目录
* 4.利用工具API方法,实现文件上传.
* 注意事项: MultipartFile 默认支持1M的数据
*/
@PostMapping("/upload")
public SysResult upload(MultipartFile file) throws IOException {
//1.获取文件名称
String fileName = file.getOriginalFilename();
//2.准备磁盘地址
String dirPath = "E:/project3/images/";
//3.将这个文件目录 封装为File对象
File dirFile = new File(dirPath);
//4.判断对象是否存在
if(!dirFile.exists()){
//如果文件目录不存在,则创建目录
dirFile.mkdirs(); //表示多级目录上传.
}
//5.封装文件全路径 E:xxx/xxx/a.jpg
String path = dirPath + fileName;
File allFile = new File(path);
//6.实现文件上传 将IO流按照指定的对象格式进行输出.
file.transferTo(allFile);
return SysResult.success();
}
}
2.2 正则表达式(复习)
2.2.1 正则表达式说明
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
总结: 正则表达式就是一种特殊格式的字符串.校验文本信息的.
2.2.2 匹配不确定次数
2.2.3 匹配固定次数
2.2.4 匹配取值区间
2.2.5 分组匹配
(jpg|png|gif)
2.2.6 正则案例练习
1.要求匹配电话号码 11位 开头都是1
正则表达式: 1[3-9][0-9]{9}
2.要求匹配邮箱 [email protected]
正则表达式:
^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+$
2.3 文件上传实现
2.3.1 编辑FileController
@RestController
@CrossOrigin
@RequestMapping("/file")
public class FileController {
@Autowired
private FileService fileService;
/**
* 业务说明: 实现图片上传
* URL: http://localhost:8091/file/upload
* 类型: post
* 参数: MultipartFile file 字节信息
* 返回值: SysResult.success()
* 问题思考:
* 1.完成图片类型校验 jpg|png|gif....
* 2.防止恶意程序 a.exe.jpg
* 3.将图片分目录存储
* 3.1.按照类型分 理论可以但是得多分配几个
* 3.2.按照时间划分. yyyy/MM/dd
* 4.自定义文件名称. 利用UUID充当图片名称.
*/
@PostMapping("/upload")
public SysResult upload(MultipartFile file) throws IOException {
ImageVO imageVO = fileService.upload(file);
if(imageVO == null){
return SysResult.fail();
}
return SysResult.success(imageVO);
}
/**
* 业务说明: 实现图片上传
* URL: http://localhost:8091/file/upload
* 类型: post
* 参数: file 字节信息
* 返回值: SysResult.success()
* 扩展:
* 一般情况下:
* 一般前端向后端服务器发送字节信息.由外到内实现数据传输.
* 采用输入流信息. InputStream file
* 使用字节流的弊端: 1.必须手动关闭, 2.代码操作繁琐
* 底层代码的实现.
* SpringMVC高级API MultipartFile 专门处理IO流操作
* 文件上传步骤:
* 1.获取文件名称
* 2.准备文件上传的目录
* 3.判断目录是否存在 存在目录: 实现上传 没有目录:创建目录
* 4.利用工具API方法,实现文件上传.
* 注意事项: MultipartFile 默认支持1M的数据
*/
/*@PostMapping("/upload")
public SysResult upload(MultipartFile file) throws IOException {
//1.获取文件名称
String fileName = file.getOriginalFilename();
//2.准备磁盘地址
String dirPath = "E:/project3/images/";
//3.将这个文件目录 封装为File对象
File dirFile = new File(dirPath);
//4.判断对象是否存在
if(!dirFile.exists()){
//如果文件目录不存在,则创建目录
dirFile.mkdirs(); //表示多级目录上传.
}
//5.封装文件全路径 E:xxx/xxx/a.jpg
String path = dirPath + fileName;
File allFile = new File(path);
//6.实现文件上传 将IO流按照指定的对象格式进行输出.
file.transferTo(allFile);
return SysResult.success();
}*/
}
2.3.2 编辑FileService
package com.jt.service;
import com.jt.vo.ImageVO;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.FileNameMap;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@Service
public class FileServiceImpl implements FileService{
private String localDirPath = "E:/project3/images";
//1.校验图片类型 xxx.jpg 校验后缀是否为jpg
@Override
public ImageVO upload(MultipartFile file) {
//1.1 获取文件名称 abc.jpg
String fileName = file.getOriginalFilename();
//1.2 全部转化为小写字母
fileName = fileName.toLowerCase();
//1.3正则校验是否为图片类型
if(!fileName.matches("^.+\\.(jpg|png|gif)$")){
//图片类型 不匹配 程序应该终止
return null;
}
//2.校验是否为恶意程序 怎么判断就是一张图 高度和宽度
//2.1 通过图片对象进行处理
try {
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
int height = bufferedImage.getHeight();
int width = bufferedImage.getWidth();
if(height == 0 || width == 0){
return null;
}
//3.将图片分目录存储 yyyy/MM/dd
String dateDir = new SimpleDateFormat("/yyyy/MM/dd/")
.format(new Date());
String dateDirPath = localDirPath + dateDir;
File dirFile = new File(dateDirPath);
if(!dirFile.exists()){
dirFile.mkdirs();
}
//4.防止文件重名 动态生成UUID.类型
//4.1 动态生成UUID
String uuid = UUID.randomUUID().toString()
.replace("-","");
//4.2 获取图片类型 abc.jpg .jpg
String fileType = fileName.substring(fileName.lastIndexOf("."));
// uuid.jpg
String newFileName = uuid + fileType;
//5.实现文件上传 1.准备全文件路径 2. 封装对象实现上传
String path = dateDirPath + newFileName;
file.transferTo(new File(path));
} catch (IOException e) {
e.printStackTrace();
return null;
}
return null;
}
}
2.4 文件删除操作
2.4.1 文件删除JS
2.4.2 文件删除业务接口
- 请求路径: http://localhost:8091/file/deleteFile
- 请求类型: delete
- 请求参数:
参数名称 | 参数说明 | 备注 |
---|---|---|
virtualPath | 文件上传的虚拟的路径 | 删除时需要磁盘路径一起删除 |
- 返回值结果:
参数名称 | 参数说明 | 备注 |
---|---|---|
status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
msg | 服务器返回的提示信息 | 可以为null |
data | 服务器返回的业务数据 | 可以为null |
2.4.3 编辑FileController
/**
* 业务说明: 文件删除操作
* URL地址: http://localhost:8091/file/deleteFile
* 请求类型: delete
* 参数: virtualPath 虚拟路径
* 返回值: SysResult对象
*/
@DeleteMapping("/deleteFile")
public SysResult deleteFile(String virtualPath){
fileService.deleteFile(virtualPath);
return SysResult.success();
}
2.4.4 编辑FileService
@Override
public void deleteFile(String virtualPath) {
String filePath = localDirPath + virtualPath;
File file = new File(filePath);
if(file.exists()){
//如果文件存在,则删除数据
file.delete();
}
}
2.5 图片路径封装
2.5.1 路径分析
- 图片网络地址: https://img14.360buyimg.com/n0/jfs/t2/ac4a3f32ea776da3.jpg
协议://域名:80/虚拟地址 - 图片地址封装: http://image.jt.com:80/2021/11/11/uuid.jpg.
2.5.2 页面URL地址封装
package com.jt.service;
import com.jt.vo.ImageVO;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.FileNameMap;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@Service
public class FileServiceImpl implements FileService{
private String localDirPath = "E:/project3/images";
private String preUrl = "http://image.jt.com";
//1.校验图片类型 xxx.jpg 校验后缀是否为jpg
@Override
public ImageVO upload(MultipartFile file) {
//1.1 获取文件名称 abc.jpg
String fileName = file.getOriginalFilename();
//1.2 全部转化为小写字母
fileName = fileName.toLowerCase();
//1.3正则校验是否为图片类型
if(!fileName.matches("^.+\\.(jpg|png|gif)$")){
//图片类型 不匹配 程序应该终止
return null;
}
//2.校验是否为恶意程序 怎么判断就是一张图 高度和宽度
//2.1 通过图片对象进行处理
try {
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
int height = bufferedImage.getHeight();
int width = bufferedImage.getWidth();
if(height == 0 || width == 0){
return null;
}
//3.将图片分目录存储 yyyy/MM/dd
String dateDir = new SimpleDateFormat("/yyyy/MM/dd/")
.format(new Date());
String dateDirPath = localDirPath + dateDir;
File dirFile = new File(dateDirPath);
if(!dirFile.exists()){
dirFile.mkdirs();
}
//4.防止文件重名 动态生成UUID.类型
//4.1 动态生成UUID
String uuid = UUID.randomUUID().toString()
.replace("-","");
//4.2 获取图片类型 abc.jpg .jpg
String fileType = fileName.substring(fileName.lastIndexOf("."));
// uuid.jpg
String newFileName = uuid + fileType;
//5.实现文件上传 1.准备全文件路径 2. 封装对象实现上传
String path = dateDirPath + newFileName;
file.transferTo(new File(path));
//6. 实现ImageVO数据的返回
//6.1 准备虚拟路径 /2021/11/11/uuid.jpg
String virtualPath = dateDir + newFileName;
//6.2 准备URL地址 域名前缀 + 虚拟路径
String url = preUrl + virtualPath;
System.out.println(url);
return new ImageVO(virtualPath,url,newFileName);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
@Override
public void deleteFile(String virtualPath) {
String filePath = localDirPath + virtualPath;
File file = new File(filePath);
if(file.exists()){
//如果文件存在,则删除数据
file.delete();
}
}
}
2.6 动态为属性赋值
2.6.1 业务需求
说明: 如果将属性写死到java类中,后期维护时 导致维护不方便.
优化: 可以通过@value注解动态赋值.
2.6.2 编辑properties配置文件
image.localDirPath=E:/project3/images
image.preUrl=http://image.jt.com
2.6.3 属性动态赋值
扫描二维码关注公众号,回复:
13226588 查看本文章