京淘项目搭建(五)

京淘项目搭建

一、数据的自动填充

1、业务需求说明

需求:数据库中每张表里,都包含创建时间/修改时间的字段。如果每次操作表,都手动的去维护时间信息,则响应开发效率,能否优化策略。
解决策略:MybatisPlus 实现自动填充功能。

2、MPAPI说明

2.1)语法规则
  1. 实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
  2. 注解填充字段 @TableField(… fill = FieldFill.INSERT) 生成器策略部分也可以配置!
2.2)添加注解
说明:
 		新增操作,需要自动填充,created/updated.
		修改操作,需要自动填充,updated
package com.jt.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

//pojo基类,完成2个任务,2个日期,实现序列化
@Data
@Accessors(chain=true)
public class BasePojo implements Serializable{
	@TableField(fill = FieldFill.INSERT)
	private Date created;	//表示入库时需要赋值

	@TableField(fill = FieldFill.INSERT_UPDATE)
	private Date updated;	//表示入库/更新时赋值.
}

2.3)编辑配置类

编辑完成之后,测试代码自动填充是否正常

@Component  //将对象交给Spring容器管理
public class MyMetaObjectHandler implements MetaObjectHandler {

    //当数据库做新增操作时,自动调用  API调用 不需要问为什么
    //metaObject对象 是MP自动填充的配置 有默认行为
    @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) {
        //获取当前时间
        Date date = new Date();
        this.setFieldValByName("updated", date, metaObject);
    }
}

二、用户操作

1、用户修改–数据回显

1.1)页面URL说明
	//1. 点击修改的按钮
	 <template slot-scope="scope">
                <el-button type="primary" icon="el-icon-edit" size="small" @click="updateUserBtn(scope.row)"></el-button>
                <el-button type="danger" icon="el-icon-delete" size="small" @click="deleteUser(scope.row)"></el-button>
      </template>
	
	//2. 按钮事件
	 async updateUserBtn(user){
        this.updateDialogVisible = true
        const {data: result} = await this.$http.get("/user/"+user.id)
        if(result.status !== 200) return this.$message.error("用户查询失败")
        this.updateUserModel = result.data
      },

1.2)查询用户的业务接口

请求路径:/user/{id}
请求类型:GET
返回值:SysResult对象

参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据返回user对象

JSON格式如下:

{
 "status":200,
 "msg":"服务器调用成功!",
 "data":{
	 "created":"2021-02-18T11:17:23.000+00:00",
	 "updated":"2021-05-17T11:33:46.000+00:00",
	 "id":1,
	 "username":"admin",
	 "password":"a66abb5684c45962d887564f08346e8d",
	 "phone":"13111112222",
	 "email":"1235678@qq.com",
	 "status":true,
	 "role":null
	 }
 }

1.3)编辑UserController

需求: 根据ID查询User信息

 /**
     * 业务: 根据ID查询用户信息
     *
     * URL:  http://localhost:8091/user/2
     * 参数:  id
     * 返回值: SysResult(User对象)
     */
    @GetMapping("/{id}")
    public SysResult getUserById(@PathVariable Integer id){

        User user = userService.getUserById(id);
        return SysResult.success(user);
    }

    /**
     * 需求: 实现用户修改操作
     * 请求类型: PUT
     * URL: /user/updateUser
     * 参数: User对象~~~~ user的JSON串  (id,phone,email)
     * 返回值: SysResult对象
     */
    @PutMapping("/updateUser")
    public SysResult updateUser(@RequestBody User user){

        userService.updateUser(user);
        return SysResult.success();
    }
1.4)编辑UserServiceImpl
 	@Override
    public User getUserById(Integer id) {

        return userMapper.selectById(id);
    }

    //参数: id主键  电话/邮箱
    //语法: 根据对象中不为null的属性当作set条件 id当作唯一where条件
    @Override
    public void updateUser(User user) {

        userMapper.updateById(user);
    }
1.5)数据回显

在这里插入图片描述

2、用户修改–数据更新操作

2.1) 页面分析
	//1.修改的JS
 	<span slot="footer" class="dialog-footer">
        <el-button @click="updateDialogVisible = false" >取 消</el-button>
        <el-button type="primary" @click="updateUser">确 定</el-button>
      </span>

在这里插入图片描述

2.2)业务接口文档说明

请求路径:/user/updateUser
请求类型:PUT
请求参数:User对象结构

参数名称参数说明备注
ID用户ID号不能为null
phone手机信息不能为null
email邮箱地址不能为null

返回值:SysResult对象

参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据返回user对象

JSON格式如下:

{
 "status":200,
 "msg":"服务器调用成功!",
 "data":{}
 }

2.3)编辑UserController
 /**
     * 业务: 根据ID删除用户信息
     * URL: /user/{id}
     * 参数: ID
     * 类型: Delete
     * 返回值: SysResult对象
     */
    @DeleteMapping("/{id}")
    public SysResult deleteUserById(@PathVariable Integer id){

        userService.deleteUserById(id);
        return SysResult.success();
    }
2.4 编辑UserServiceImpl
 /* 删除用户 */
    @Override
    public void deleteUser(Integer id) {
        userMapper.deleteById(id);
    }

三、关于事务说明

1、什么是事务

说明:如果后台服务器执行正常,则业务正确,事务提交. 如果业务执行失败.事务应该回滚.

2、现有代码的业务测试

说明:如图如果程序执行过程中有报错信息,应该实现事务的回滚,但是发现现有代码有2个问题
1:没有添加事物。
2:后台服务器报错之后,用户没有提示
在这里插入图片描述

3、添加事物—@Transactional注解

/**
	 * 关于Spring中的事务策略说明
	 *  0.Spring内部有事务的管理器,默认开启.
	 *  1.Spring只负责拦截运行时异常.
	 *    异常类型:  1.运行时异常  2.检查异常/编译异常 由程序员自己控制
	 *  2.属性1: rollbackFor 可以配置特殊的异常类型.遇到某种异常回滚.
	 *    属性2: noRollbackFor 可以配置异常类型 遇到某种异常不回滚.
	 * @param id
	 */
	@Override
	@Transactional //Spring默认提供的事务控制的注解
	public void deleteUser(Integer id){
		userMapper.deleteById(id);
	}

4、全局异常的处理机制

4.1)常规操作

说明:一般控制异常信息,通常情况下需要添加try-catch 用法.
弊端:所有的方法都需要try-catch的控制,必然导致代码的结构复杂.
解决方案:Spring内部提供了一种规则全局异常的处理机制
在这里插入图片描述

4.2)全局异常处理机制
package com.jt.advice;

import com.jt.vo.SysResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * Spring为了整合全局异常的处理  开发了如下的注解
 *  1.@RestControllerAdvice //定义全局异常的处理类 返回值JSON串
 *  2.@ExceptionHandler     标识拦截的异常的类型,如果类型匹配,则执行方法
 */
@RestControllerAdvice
public class MyExceptionAdvice {

    //写法:1.运行时异常(通用)  2.自定义异常信息  3.拦截所有异常Exception.class
    @ExceptionHandler(RuntimeException.class)
    public Object exception(Exception e){
        e.printStackTrace();    //输出异常信息
        //需求: 如果遇到异常,应该提示用户201/失败信息.
        return SysResult.fail();
    }
}


四、商品分类业务实现

1、实现商品分类页面跳转

编辑路由,实现商品分类操作

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import ElementUI from '../components/ElementUI.vue'
import Home from '../components/Home.vue'
import User from '../components/user/user.vue'
import Item from '../components/items/Item.vue'
import Welcome from '../components/Welcome.vue'
import ItemCat from '../components/items/ItemCat.vue'

//使用路由机制  通过children实现路由嵌套, redirect重定向
Vue.use(VueRouter)
const routes = [
  {path: '/', redirect: '/login'},
  {path: '/login', component: Login},
  {path: '/elementUI', component: ElementUI},
  //children组件的跳转 在home组件内部进行填充
  {path: '/home', component: Home,  redirect: '/welcome', children:[
    {path: '/welcome', component: Welcome},
    {path: '/user', component: User},
    {path: '/item', component: Item},
    {path: '/itemCat', component: ItemCat}
  ]}
]

//配置路由对象
const router = new VueRouter({
  routes
})

/* 配置路由导航守卫 控制权限
  1.to 要跳转的网址
  2.from 请求从哪里来
  3.next 回调函数  放行/跳转
 */
router.beforeEach((to,from,next) => {
  //1.如果用户访问 /login  请求应该放行 终止程序
  if(to.path === '/login') {
    return next()
  }

  //2.如果用户访问不是login 则需要校验是否登录 检查是否有token
  let token = window.sessionStorage.getItem('token')
  if(token !== null && token.length > 0){
    return next()
  }else {
    //没有token 应该跳转到登录页面 "/login"
    return next("/login")
  }

  //if(token) if的一种简化写法 解析: 如果token不为null
  //if(!token)  解析: token为null
})

export default router

在这里插入图片描述

2、ItemCat 说明

2.1)表设计说明

在这里插入图片描述

2.2)ItemCat POJO说明
package com.jt.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.List;


@TableName("item_cat")
@Data
@Accessors(chain = true)
public class ItemCat extends BasePojo{

    @TableId(type = IdType.AUTO)
    private Integer id;         //定义主键
    private Integer parentId;   //定义父级菜单
    private String name;        //分类名称
    private Boolean status;     //分类状态 0 停用 1 正常
    private Integer level;      //商品分类等级  1 2 3
    @TableField(exist = false)
    private List<ItemCat> children;
}

2.3)商品分类业务说明
2.3.1)京东官网商品分类介绍

在这里插入图片描述

2.3.2)如何维护父子关系

表:id 与 parent_id
对象:this–children

2.3.3)三级菜单说明–Sql查询

在这里插入图片描述

2.3.4)如何利用对象封装3级菜单结构?

一级菜单
children-----> 二级菜单信息
children-------> 三级菜单信息
在这里插入图片描述

3、商品分类列表实现

3.1)业务需求

当用户点击商品分类列表时,应该采用三级商品分类的结构实现列表的展现.

3.2)页面JS说明
	//1. 生命周期函数说明
	created() {
      //默认获取商品分类列表数据
      this.findItemCatList()
    },

	//2.业务方法说明
	  async findItemCatList() {
        const { data: result }
          = await this.$http.get("/itemCat/findItemCatList/3")
        if (result.status !== 200) return this.$message.error("获取商品分类列表失败!!")
        this.itemCatList = result.data
      },
	

3.3 业务接口文档说明

请求路径:/itemCat/findItemCatList/{level}
请求类型:get
请求参数:level

参数名称参数说明备注
level查询级别1查询一级分类 2查询1-2 级商品分类 3查询1-2-3级商品分类

业务说明:查询3级分类菜单数据 要求三层结构嵌套
返回值:SysResult对象

参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据3级商品分类信息

4、编辑ItemCatController

package com.jt.controller;

import com.jt.pojo.ItemCat;
import com.jt.service.ItemCatService;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@CrossOrigin
@RequestMapping("/itemCat")
public class ItemCatController {

    @Autowired
    private ItemCatService itemCatService;

    /**
     * 需求: 查询3级商品分类列表信息
     * URL:  /itemCat/findItemCatList/{level}
     * 参数:  level 查询的层级
     * 返回值: SysResult对象(List<ItemCat>)
     */
    @GetMapping("/findItemCatList/{level}")
    public SysResult findItemCatList(@PathVariable Integer level){

        List<ItemCat> itemCatList = itemCatService.findItemCatList(level);
        return SysResult.success(itemCatList);
    }
}

5、编辑ItemCatService—for循环

1.0版本: for循环嵌套结构 暂时不考虑level 最好理解的

package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.ItemCatMapper;
import com.jt.pojo.ItemCat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ItemCatServiceImpl implements ItemCatService{

    @Autowired
    private ItemCatMapper itemCatMapper;

    /**
     * 业务: 查询3级商品分类信息
     *      1. 一级中嵌套二级集合
     *      2. 二级菜单嵌套三级集合.
     *
     * 1.0版本: for循环嵌套结构  暂时不考虑level 最好理解的
     * 常识:
     *      1.用户第一次查询数据库 需要建立链接.
     *      2.第二次查询 从链接池中动态获取链接 所以速度更快!!!
     *
     *  思考: 该业务查询了多少次数据库??? 第一层循环10个  第二层循环10 总查询数=10*10=100次
     *       如何优化查询策略!!!!
     * @param level
     * @return
     */
    @Override
    public List<ItemCat> findItemCatList(Integer level) {
        //性能问题:!!!!!
        long startTime = System.currentTimeMillis();

        //1.查询一级商品分类信息
        QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", 0);
        List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);

        //2.查询二级商品分类信息  遍历一级集合
        for(ItemCat oneItemCat : oneList){
            queryWrapper.clear();   //清空条件
            queryWrapper.eq("parent_id", oneItemCat.getId());
            List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);

            //3.查询三级商品分类信息  遍历
            for(ItemCat twoItemCat : twoList){
                queryWrapper.clear();
                queryWrapper.eq("parent_id", twoItemCat.getId());
                List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);
                //将三级封装给二级
                twoItemCat.setChildren(threeList);
            }
            //3.将二级记录封装给一级
            oneItemCat.setChildren(twoList);
        }

        //记录程序的结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("查询耗时:"+(endTime - startTime)+"毫秒");
        return oneList;
    }
}

6、页面效果展现

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AimerDaniil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值