一、实现商品分类查询
1、将数据导入Map集合
/**
* 实现商品分类查询
* Map<Integer,List<ItemCat>>
* 0,一级菜单集合
* 一级Id,二级菜单集合
* 二级Id,三级菜单集合
* 业务思路:
* 判断是否已经存在parentId
* 不存在: 我是第一个元素 封装到list中 之后保存到Map中
* 存在: 获取list集合,将自己追加到其中
* 扩展知识: map每次都需要查询数据库,如果采用redis缓存,则性能极大的提升 2ms完成查询
*/
public Map<Integer,List<ItemCat>> getMap(){
//1.查询全部数据库记录
List<ItemCat> list = itemCatMapper.selectList(null);
//2.将list集合数据,封装到Map集合中
Map<Integer,List<ItemCat>> map = new HashMap<>();
for (ItemCat itemCat : list) { //遍历所有的数据
int parentId = itemCat.getParentId();
//containsKey: 检查key值存不存在
if (map.containsKey(parentId)) { //key存在,将数据追加即可
map.get(parentId).add(itemCat);
} else {//key不存在 我是当前parentId的第一个子级
List<ItemCat> temp = new ArrayList<>();
temp.add(itemCat);
map.put(parentId,temp);
}
}
return map;
}
2、获取一级、二级、三级菜单
//Map<parentId,List<ItemCat>子级>
@Override
public List<ItemCat> findItemCatList(Integer level) {
Map<Integer,List<ItemCat>> map = getMap();
if (level == 1){
return map.get(0);
}
if (level == 2){ //查询一级和二级
return getTwoList(map);
}
return getThreeList(map);
}
//获取一级 / 二级 / 三级菜单
private List<ItemCat> getThreeList(Map<Integer, List<ItemCat>> map) {
//1.获取一级和二级
List<ItemCat> oneList = getTwoList(map);//一级数据不可能为空
//2.遍历一级集合 获取二级的数据
for (ItemCat oneItemCat : oneList){
//二级数据可能为null
List<ItemCat> twoList = oneItemCat.getChildren();
if (twoList == null || twoList.size() == 0){
//表示数据没有二级 本次循环应该终止,开始下一次循环
continue;
}
//二级列表一定有值,可以查询三级列表
for (ItemCat twoItemCat : twoList){
//获取二级Id 查询三级数据
int parentId = twoItemCat.getId();
List<ItemCat> threeList = map.get(parentId);
//将三级数据保存到二级数据中
twoItemCat.setChildren(threeList);
}
}
return oneList;
}
//获取二级菜单
private List<ItemCat> getTwoList(Map<Integer, List<ItemCat>> map) {
//1.获取一级菜单
List<ItemCat> oneList = map.get(0);
//2.遍历数据
for (ItemCat oneItemCat : oneList){
//key
int parentId = oneItemCat.getId();
//根据父级查询子级
List<ItemCat> twoList = map.get(parentId);
//封装子级数据
oneItemCat.setChildren(twoList);
}
return oneList;
}
二、application文件
#配置端口号
server:
port: 8091
#管理数据源
spring:
datasource:
#高版本驱动使用
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
#设定用户名和密码
username: root
password: 2323
#SpringBoot整合Mybatis-plus
mybatis-plus:
#指定别名包
type-aliases-package: com.jt.pojo
#扫描指定路径下的映射文件
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
# 一二级缓存默认开始 所以可以简化
#打印mysql日志
logging:
level:
com.jt.mapper: debug
三、自动填充操作时间
BasePojo类:数据创建时间以及修改时间
//pojo基类,完成2个任务,2个日期,实现序列化
@Data
@Accessors(chain=true)//控制是否开启链式加载结构
public class BasePojo implements Serializable{
//新增操作时,自动填充
@TableField(fill = FieldFill.INSERT)
private Date created; //表示入库时需要赋值
//@TableField MybatisPlus注解 标识属性是否存在,及名称是否一致
//新增-修改操作时,自动填充
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updated; //表示入库/更新时赋值.
}
MyMetObjectHandler配置类:实现自动填充
@Component //将当前类未来的对象交给容器管理
public class MyMetObjectHandler implements MetaObjectHandler {
//优势: 以后操作数据表无需手动操作时间!!! 都会自动填充
@Override
public void insertFill(MetaObject metaObject) {
Date date = new Date();
this.setFieldValByName("created", date, metaObject);
this.setFieldValByName("updated", date, metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updated", new Date(), metaObject);
}
}
四、商品分页展现
1、PageResult类
@Data
@Accessors(chain = true)
public class PageResult implements Serializable {
private String query; //用户查询的数据
private Integer pageNum; //查询页数
private Integer pageSize; //查询条数
private Long total; //查询总记录数
private Object rows; //分页查询的结果
}
2、分页步骤
@Override
public PageResult getItemList(PageResult pageResult) {
//1.用户查询的where条件
QueryWrapper<Item> queryWrapper = new QueryWrapper<>();
boolean flag = StringUtils.hasLength(pageResult.getQuery());//判断字符串是否为空
queryWrapper.like(flag,"title", pageResult.getQuery());
//2.page是MP分页对象 参数1:页数 参数2:条数
Page<Item> page =
new Page<>(pageResult.getPageNum(),pageResult.getPageSize());
//MP在内部自动的获取 总数和分页后的结果
page = itemMapper.selectPage(page,queryWrapper);
//3.获取数据之后封装
long total = page.getTotal();
List<Item> rows = page.getRecords();
return pageResult.setTotal(total).setRows(rows);
}
3、添加配置类
@Configuration //添加配置类
public class MybatisPlusConfig {
// 最新版
// 核心功能: 指定数据库版本,自动生成Sql
@Bean //标识该方法的返回值交给Spring容器管理
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB));
return interceptor;
}
}
五、商品图片上传
1、SysResult类
@Data
@Accessors(chain = true)//控制是否开启链式加载结构
@NoArgsConstructor //生成无参构造方法
@AllArgsConstructor //生成全参构造方法
public class SysResult implements Serializable {//实现了序列化的接口
private Integer status; //200成功 201失败
private String msg; //提示信息
private Object data; //服务器返回值数据
public static SysResult fail(){//失败
return new SysResult(201,"业务调用失败!!",null);
}
public static SysResult success(){//成功
return new SysResult(200,"业务调用成功!!",null);
}
public static SysResult success(Object data){
return new SysResult(200,"业务调用成功!!",data);
}
public static SysResult success(String msg,Object data){
return new SysResult(200,msg,data);
}
}
2、ImageVO类
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {
private String virtualPath; //动态变化的路径
private String urlPath; //网络地址
private String fileName; //图片名称
}
3、FileServiceImpl类
@Service
public class FileServiceImpl implements FileService{
//定义根目录 windows系统采用该目录 Linux系统需要切换目录
private String preFilePath = "D:/software/image";
//定义网络地址前缀
private String preURLPath = "http://image.jt.com";
/**
* 实现图片上传
* 业务思路:
* 1.校验图片的类型 jpg|png|gif
* 2.校验是否为恶意程序 木马.exe.jpg
* 3.将图片进行分目录存储 hash方式存储|时间格式存储
* 4.防止图片重名,使用UUID.
* @param file
* @return
*/
@Override
public ImageVO upload(MultipartFile file) {
//1.获取文件名称 abc.jpg
//2.bug: 文件名称大小写问题 全部转化为小写
String fileName = file.getOriginalFilename().toLowerCase();
if (!fileName.matches("^.+\\.(jpg|png|gif)$")){
//如果图片不满足条件,则程序终止
return null;
}
//第二步: 校验是否为恶意程序
try {
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
int height = bufferedImage.getHeight();
int width = bufferedImage.getWidth();
if (height==0 || width==0){
return null;
}
//第三步: 分目录储存 提高检索的效率 按照时间将目录划分 /yyyy/MM/dd/
String datePath =
new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
//D:/software/lsy/image/2022/01/25
String fileDir = preFilePath + datePath;
//创建目录
File dirFile = new File(fileDir);
if (!dirFile.exists()){ //目录没有的时候,应该创建目录
dirFile.mkdirs();
}
//第四步: 防止文件重名
String uuid = UUID.randomUUID().toString().replace("-", "");
int index = fileName.lastIndexOf(".");
//获取数据.jpg
String fileType = fileName.substring(index);
//新文件名称
fileName = uuid + fileType;
//第五步: 实现文件上传
//D:/software/lsy/image/2022/01/25/uuid.jpg
String filePath = fileDir + fileName;
file.transferTo(new File(filePath));
//第六步: 封装ImageVO返回数据 /2022/01/25/uuid.jpg
String virtualPath = datePath + fileName;
//第七步: 封装网络地址 http://image.jt.com/2022/01/25/uuid.jpg
String urlPath = preURLPath + virtualPath;
System.out.println(urlPath);
return new ImageVO(virtualPath,urlPath,fileName);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}