1. 实现商品详情展示
1.1 业务阐明
个别用户查问商品时, 只须要展示商品相干信息即可, 如果用户点击某个商品时才会展示商品详情信息, 因为商品详情是大字段信息, 所以检索绝对较慢, 节约性能.
表设计说明:
1.tb_item 商品表
2.tb_item_desc 商品详情表
一个商品只有一个详情信息, 所以 item 表与 itemDesc 一对一.
1.2 商品详情表设计
1.3 编辑 ItemDesc
package com.jt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@TableName("tb_item_desc")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class ItemDesc extends BasePojo{
@TableId
private Long itemId; // 商品 ID 与 item 表中的数据统一.
private String itemDesc; // 商品详情
}
1.4 富文本编辑器介绍
1.4.1 入门案例
1.5 重构商品新增
1.5.1 业务阐明
因为商品新增是将 Item/ItemDesc 对象一起新增, 所以须要实现 2 张表的入库操作.
1.5.2 编辑 ItemController
/**
* 业务需要: 实现商品新增操作
* url: http://localhost:8091/item/save
* 参数: 整个表单进行提交 应用对象接管
* 返回值: 零碎返回值对象
*/
@RequestMapping("/save")
@Transactional
public SysResult saveItem(Item item, ItemDesc itemDesc) {itemService.saveItem(item,itemDesc);
return SysResult.success();}
1.5.3 编辑 ItemService
@Override
@Transactional// 开启事务管制
public void saveItem(Item item, ItemDesc itemDesc) {
//MP 用法:如果实现主键自增, 则主动的实现数据的回显!!!
itemMapper.insert(item);
// 获取主键信息
itemDesc.setItemId(item.getId());
itemDescMapper.insert(itemDesc);
}
1.6 商品详情展示
1.6.1 页面剖析
1.6.2 页面 JS 剖析
1.6.3 编辑 ItemController
@RequestMapping("/query/item/desc/{itemId}")
public SysResult findItemDescById(@PathVariable Long itemId){ItemDesc itemDesc=itemService.findItemDescById(itemId);
return SysResult.success(itemDesc);
}
1.6.4 编辑 ItemService
@Override
public ItemDesc findItemDescById(Long itemId) {return itemDescMapper.selectById(itemId);
}
1.6.5 页面成果展示
1.7 重构商品更新
1.7.1 业务阐明
当用户点击商品更新时, 应该实现 2 张表的数据更新操作. 更新 Item/ 更新 ItemDesc 对象
1.7.2 编辑 ItemController
/**
* 实现商品编辑
* url 地址: /item/update
* 申请参数: 整个 form 表单提交
* 返回值: sysResult 对象
*/
@RequestMapping("/update")
public SysResult updateItem(Item item,ItemDesc itemDesc) {itemService.updateItem(item,itemDesc);
return SysResult.success();}
1.7.3 编辑 ItemService
@Override
@Transactional // 管制事务
public void updateItem(Item item, ItemDesc itemDesc) {itemMapper.updateById(item);
// 补全数据
itemDesc.setItemId(item.getId());
itemDescMapper.updateById(itemDesc);
}
1.8 商品删除操作
1.8.1 编辑 ItemController
/**
* 实现商品的删除
* url:/item/delete
* 参数:ids
* 返回类型:SysResult
*/@RequestMapping("/delete")
public SysResult deleteItems(Long[] ids) {itemService.deleteItems(ids);
return SysResult.success();}
1.8.2 编辑 ItemService
@Override
@Transactional
public void deleteItems(Long[] ids) {
// 形式 2 手写 sql 形式实现删除
itemMapper.deleteItems(ids);
// 商品详情信息
List<Long> longIds= Arrays.asList(ids);
itemDescMapper.deleteBatchIds(longIds);
}
2 文件上传
2.1 文件上传入门案例
2.1.1 页面标识
2.1.2 文件上传入门案例
package com.jt.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@RestController
public class FileController {
/**
* url 地址: http://localhost:8091/file
* 参数: 文件信息 fileImage
* 返回值: String
*/
@RequestMapping("/file")
public String file(MultipartFile fileImage) throws IOException {
//1. 获取图片名称
String name = fileImage.getOriginalFilename();
//2. 定义文件目录
String fileDirPath = "D:/JT-SOFT/images";
//3. 创立目录
File fileDir = new File(fileDirPath);
if(!fileDir.exists()){fileDir.mkdirs();
}
//4. 生成文件的全门路
String filePath = fileDirPath+"/"+name;
File imageFile = new File(filePath);
//5. 实现文件上传
fileImage.transferTo(imageFile);
return "文件上传胜利!!!";
}
}
2.2 实现文件上传
2.2.1 页面 URL 剖析
2.2.2 申请参数
2.2.3 编辑 VO 对象
{“error”:0,“url”:“图片的保留门路”,“width”: 图片的宽度,“height”: 图片的高度}
package com.jt.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {//{"error":0,"url":"图片的保留门路","width": 图片的宽度,"height": 图片的高度}
private Integer error; // 0 示意文件上传正确 1. 上传有误
private String url; // 图片浏览的网络地址(虚拟地址)
private Integer width; // 宽度
private Integer height; // 高度
public static ImageVO fail(){return new ImageVO(1, null, null, null);
}
public static ImageVO success(String url,Integer width,Integer height){return new ImageVO(0, url,width, height);
}
}
2.2.4 编辑 FileController
/**
* 业务需要: 实现文件上传操作
* url:http://localhost:8091/pic/upload?dir=image
* 参数:uploadFile
* 返回值: ImageVO 对象
*/
@RequestMapping("/pic/upload")
public ImageVO upload(MultipartFile uploadFile){return fileService.upload(uploadFile);
}
2.2.5 编辑 pro 配置文件
# 配置本地磁盘根目录
image.fileDir=E:/images
#配置图片服务器地址
image.urlPath=http://image.ji.com
2.2.6 编辑 FileService
package com.jt.service;
import com.jt.vo.ImageVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
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.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Service
@PropertySource(value="classpath:/properties/image.properties",encoding="UTF-8")
public class FileServiceImpl implements FileService {@Value("${image.fileDir}")
private String fileDir;//"E:/images"
@Value("${image.urlPath}")
private String urlPath;// 设定域名网址
private static Set<String> typeSet = new HashSet<>();
static {typeSet.add(".jpg");
typeSet.add(".png");
typeSet.add(".gif");
}
/**
* 业务逻辑: 实现文件上传 @Override
* 步骤:
* 1. 校验图片的类型 jpg|png|gif.......
* 2. 校验文件是否为恶意程序...
* 3. 采纳分目录的构造进行存储
* 4. 防止文件重名 UUID
* @param uploadFile
* @return
*/
@Override
public ImageVO upload(MultipartFile uploadFile) {
// 一. 校验图片类型 1. 利用汇合校验 2. 正则表达式
//1.1 获取文件名称 1.jpg 1.JPG}
String fileName = uploadFile.getOriginalFilename();
// 全副转化为小写
fileName = fileName.toLowerCase();
//1.2 获取文件后缀类型
int index = fileName.lastIndexOf(".");
//1.3 .jpg
String fileType = fileName.substring(index);
//1.4 判断是否为图片类型
if (!typeSet.contains(fileType)) {return ImageVO.fail();
}
// 二. 如果是图片,高度、宽度
//2.1 将数据转化图片对象
try {BufferedImage bufferedImage=ImageIO.read(uploadFile.getInputStream());
int width=bufferedImage.getWidth();
int height=bufferedImage.getHeight();
if (width==0||height==0){return ImageVO.fail();
}
// 三. 实现分目录贮存
//3.1 依照 /yyyy/MM/dd/ 的形式进行目录划分
String dateDir=new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
//E:/images/2020/12/01
String fileDirPath=fileDir+dateDir;
File dirFile=new File(fileDirPath);
//3.2 创立目录
if (!dirFile.exists()){dirFile.mkdirs();
}
// 四. 实现文件上传
//4.1 筹备文件名称 UUID
String uuid= UUID.randomUUID().toString().replace("-","");
//4.2 动静生成文件名称
String uuidName=uuid+fileType;
//4.3 实现文件上传 E:images20201202a.jpg
File realFile=new File(fileDirPath+uuidName) ;
uploadFile.transferTo(realFile);
// 本地磁盘地址:E:images20201202a.jpg
// 网络拜访虚拟地址:http://image.ji.com20201202a.jpg
String url=urlPath+dateDir+uuidName;
return ImageVO.success(url,width,height);
} catch (IOException e) {e.printStackTrace();
}
return null;
}
}
2.2.7 代码测试
1. 上传图片之后 文件上传的门路.
2. 将申请的前缀批改为具体磁盘地址
切换前缀, 查看文件是否失常