Java入门项目之京淘电商后台管理系统

本文档详细介绍了Spring的@RestControllerAdvice如何实现全局异常处理,包括自定义异常类和返回结果。同时,展示了用户登录、商品管理和权限管理等业务场景的实现,涉及到登录安全(token)、分页查询、商品分类查询和删除等操作。此外,还讨论了在处理多级分类信息时的性能优化策略。
摘要由CSDN通过智能技术生成

目录

异常处理

业务返回

用户登录

登录安全问题(token)

业务实现

业务需求文档

用户管理

用户列表

列表分页

商品管理

商品列表

列表分页

商品分类

查询商品等级分类信息

删除商品等级分类信息

权限管理

数据统计



异常处理

Spring为了整合全局异常的处理(不用在每个方法下捕获或者抛出异常从而达到处理异常的机制),开发了如下注解:

  1. @RestControllerAdvice 定义全局异常的处理类 返回值JSON串
  2. @ExceptionHandler 标识拦截的异常的类型,如果类型匹配,则执行方法
@RestControllerAdvice
public class MyExceptionAdvice {
    //写法:1.运行时异常(通用) 2.自定义异常信息 3.拦截所有异常Exception
    @ExceptionHandler(RuntimeException.class)
    public Object exception(Exception e){
        //需求: 如果遇到异常,应该提示用户201/失败信息.
        e.printStackTrace();
        return SysResult.fail();
    }
}

业务返回

满足不同业务需求的返回不同结果,方便前端识别业务执行成功与否,以便执行不同的操作.

@Data
@Accessors(chain = true)
@NoArgsConstructor//无参构造
@AllArgsConstructor//全参构造
public class SysResult implements Serializable {//实现接口是一种规范性写法
    private Integer status;//状态码信息200 201
    private String msg;//服务器返回的提示信息
    private Object data;//返回的业务数据,不清楚是什么类型,就用object
    //为了用户使用VO对象更加的方便,重载一些方法,简化程序的调用
    public static SysResult fail(){
        return new SysResult(201,"业务执行失败",null);
    }
    //1.不带参数的正确返回
    public static SysResult success(){
        return new SysResult(200,"业务执行成功",null);
    }
    //2.带返回值的正确返回  用户传递什么/返回值就是什么
    public static SysResult success(Object data){
        return new SysResult(200,"服务器处理成功",data);
    }
    //3.带返回值,带提示信息
    public static SysResult success(String msg, Object data){
        return new SysResult(200,msg,data);
    }
}

用户登录

登录安全问题(token)

为了防止直接跳转网页,用户登录成功后会返回一个token标识,后续跳转页面时,会监测是否带有token标识,有则可以跳转,没有则不能执行相关业务.若后续关闭系统则需要重新登录并获取token标识.

业务实现

业务需求文档

  • 需求:检测用户登录操作
  • URL: /login
  • 请求类型: Post请求
  • 接收参数: User对象
  • 返回值: Sysresult对象

Controller层:

//检测用户登录操作
    @PostMapping("/login")
    public SysResult login(@RequestBody User user){
        System.out.println(user);
        //token用于用户名和密码的校验,防止直接跳转网页
        //token 有值则业务正确  null 业务操作失败
        String token = userService.login(user);
        if (token == null){
            return SysResult.fail();
        }
        return SysResult.success(token);
    }

Service层:

public String login(User user) {
        String password = user.getPassword();//明文密码,需要加密,利用DigestUtils
        //byte[] passByte = password.getBytes();
        String md5Pass = DigestUtils.md5DigestAsHex(password.getBytes());
        //根据用户名和密文查询数据库
        //根据对象中不为null的属性充当where条件
        user.setPassword(md5Pass);
        QueryWrapper<User> qw = new QueryWrapper<>(user);
        User userDB = userMapper.selectOne(qw);
        //查询结果是否有效
        if (userDB == null){//用户名密码错误 返回null
            return null;
        }
        //用户名密码均正确 返回一个独一无二的token 利用UUID
        return UUID.randomUUID().toString()
                        .replace("-", "");
    }

用户管理

用户列表

列表分页

  • 需求:分页查询用户列表信息
  • URL:/list?query,pagenum,pagesize
  • 请求类型:get
  • 接收参数:PageResult对象
  • 返回值:SysResult

Controller层:

/**
     *  获取用户列表信息
     *  参数:PageResult对象进行接收 传递3个参数
     *  返回值:SysResult对象 参数(PageResult对象)  返回5个参数
     *  我们想要的数据封装在sysResult对象的data属性里,data属性也即PageResult对象,
     *  前端再根据需要,从data属性里面抽取需要的数据
     */
    @GetMapping("/list")
    public SysResult getUserList(PageResult pageResult){
        return SysResult.success(userService.getUserList(pageResult));
    }

Service层:

public PageResult getUserList(PageResult pageResult){
        //参数1: page分页对象
        Page page = new Page(pageResult.getPageNum(),pageResult.getPageSize());
        //参数2:分页的查询条件 username模糊查询 注意bug:如果用户没有传递query,模糊查询一样拼接,与理想不符
        QueryWrapper<User> qw = new QueryWrapper<>();
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        qw.like(flag,"username",pageResult.getQuery());
        //page 原本两个参数 根据分页查询返回 total/分页后的记录records 4个参数
        page = userMapper.selectPage(page, qw);

        List<User> userList = page.getRecords();
        long total = page.getTotal();
        System.out.println(total);

        return pageResult.setTotal(total).setRows(userList);
    }

商品管理

商品列表

列表分页

  • 需求:分页查询商品
  • URL:/item/getItemList?query,pagenum,pagesize
  • 请求类型:get
  • 接收参数:PageResult对象
  • 返回值:Sysresult

Controller层:

@GetMapping("/getItemList")
    public SysResult getItemList(PageResult pageResult){
        pageResult = itemService.getItemList(pageResult);
        return SysResult.success(pageResult);
    }

Service层:

public PageResult getItemList(PageResult pageResult) {
        Page<Item> page = new Page<>(pageResult.getPageNum(),pageResult.getPageSize());
        QueryWrapper<Item> qw = new QueryWrapper<>();
        //query有值才拼接
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        qw.like(flag, "title", pageResult.getQuery());
        page = itemMapper.selectPage(page, qw);
        return pageResult.setTotal(page.getTotal()).setRows(page.getRecords());
    }

商品分类

查询商品等级分类信息

  • 需求:按照商品的level等级,查询出对应等级的商品分类信息
  • URL:/itemCat/findItemCatList/{level}
  • 请求类型:get
  • 接收参数:level
  • 返回值:SysResult对象

Controller层:

@GetMapping("/findItemCatList/{level}")
    public SysResult findItemCatList(@PathVariable Integer level){
        List<ItemCat> itemCatList = itemCatService.findItemCatList(level);
        return SysResult.success(itemCatList);
    }

Service层:

方式1:利用map集合封装所有的父子级关系

public List<ItemCat> findItemCatList(Integer level) {
        long start = System.currentTimeMillis();
        //map集合封装的是所有父子级关系
        Map<Integer,List<ItemCat>> map = initMap();
        //只获取一级,即parend_id=0
        if (level == 1) return map.get(0);
        //获取二级 1/2
        if (level == 2) return getLevel2List(map);
        //获取1/2/3级
        else return getLevel3List(map);
    }
/**
     * 1.封装Map集合 Map<父级id,list<ItemCat>,value里的数据是key对应数据的子级,只有父子级关系(并不是一二级)
     *     只查询一次数据库,作为辅助方法
     * @return
     */
    public Map<Integer, List<ItemCat>> initMap() {
        Map<Integer,List<ItemCat>> map = new HashMap<>();
        //1.查询item_cat表中的所有记录(1/2/3级菜单)
        List<ItemCat> itemCatList = itemCatMapper.selectList(null);
        //2.实现数据封装
        /**
         * 1.key不存在,准备一个新的list集合,直接追加到list集合
         * 2.key存在,获取原有list集合,再追加
         */
        for (ItemCat itemCat: itemCatList){
            //key存在,获取原有list集合,再追加
            if (map.containsKey(itemCat.getParentId()))
                map.get(itemCat.getParentId()).add(itemCat);
            //key不存在,准备一个新的list集合,直接追加到list集合
            else {
                List<ItemCat> list = new ArrayList<>();
                list.add(itemCat);
                map.put(itemCat.getParentId(), list);
            }
        }
        return map;//将封装的数据进行返回
    }

//查询一级和二级信息
    public List<ItemCat> getLevel2List(Map<Integer, List<ItemCat>> map) {
        //先遍历一级,再封装二级
        //1.获取一级
        List<ItemCat> oneList = map.get(0);
        for (ItemCat oneItemCat: oneList){
            //查询二级,通过一级的id
            List<ItemCat> twoList = map.get(oneItemCat.getId());
            oneItemCat.setChildren(twoList);
        }
        return oneList;
    }
    //查询一级/二级/三级
    public List<ItemCat> getLevel3List(Map<Integer, List<ItemCat>> map) {
        List<ItemCat> oneList = getLevel2List(map);
        //遍历一级,获取二级
        for (ItemCat oneItemCat: oneList){
            List<ItemCat> twoList = oneItemCat.getChildren();
            //如果当前一级没有二级,直接跳过当前循环
            if (twoList == null || twoList.size() == 0) continue;
            //若一级下面有二级,则查询三级
            for (ItemCat twoItemCat: twoList){
                List<ItemCat> threeList = map.get(twoItemCat.getId());//获取以二级id为父级的子级
                twoItemCat.setChildren(threeList);//封装为二级的子级
            }
        }
        return oneList;
    }

 方式2:利用多重for循环

public List<ItemCat> findItemCatList(Integer level) {
        //1.查询一级商品分类信息
        QueryWrapper<ItemCat> qw = new QueryWrapper<>();
        qw.eq("parent_id", 0);
        List<ItemCat> oneLists = itemCatMapper.selectList(qw);
        for (ItemCat oneItemCat: oneLists){
            qw.clear();
            qw.eq("parent_id", oneItemCat.getId());
            List<ItemCat> twoLists = itemCatMapper.selectList(qw);
            //不能再次将二级记录封装给一级,如果在这里封装,则二级的children为null
            //oneItemCat.setChildren(twoLists);
            for (ItemCat twoItemCat: twoLists){
                qw.clear();
                qw.eq("parent_id", twoItemCat.getId());
                List<ItemCat> threeLists = itemCatMapper.selectList(qw);
                //将三级记录封装给二级
                twoItemCat.setChildren(threeLists);
            }
            //将二级记录封装给一级
            oneItemCat.setChildren(twoLists);
        }
        return oneLists;
    }

常识:用户第一次查询数据库,需要建立链接,相对耗时长,但是后续查询是直接从链接池中动态获取链接,速度明显会加快.

for循环操作性能低:查询数据库的次数与for循环的层数和每层次数相关.

封装map集合:只查询一次数据库,作为辅助集合,后续业务都是对map集合进行相关操作,就不需要建立链接了,性能大幅度提高.

删除商品等级分类信息

  • 需求:按照level商品等级信息,删除对应id分类信息
  • URL:/itemCat/deleteItemCat + id/level
  • 请求类型:delete
  • 接收参数:ItemCat对象
  • 返回值:SysResult

Controller层:

@DeleteMapping("/deleteItemCat")
    public SysResult deleteItemCat(ItemCat itemCat){
        itemCatService.deleteItemCat(itemCat);
        return SysResult.success();
    }

 Service层:

@Transactional//添加事务
    public void deleteItemCat(ItemCat itemCat) {
        if (itemCat.getLevel() == 3) itemCatMapper.deleteById(itemCat.getId());
        if (itemCat.getLevel() == 2) {
            /*方式1
            QueryWrapper<ItemCat> qw = new QueryWrapper<>();
            qw.eq("parent_id", itemCat.getId());//只是删除当前二级下的所有三级数据,不用遍历所有的二级
            List<ItemCat> threeList = itemCatMapper.selectList(qw);
            //遍历删除三级*/
            //方式2
            QueryWrapper<ItemCat> qw = new QueryWrapper<>();
            qw.eq("parent_id",itemCat.getId());
            itemCatMapper.delete(qw);//删除三级
            itemCatMapper.deleteById(itemCat.getId());//直接删除二级
        }
        else {//先删3,再删2,再删1
            List<Integer> ids = new ArrayList<>();//用于存放要删除的二级id
            //1.查询当前一级下的所有二级
            QueryWrapper<ItemCat> qw = new QueryWrapper<>();
            qw.eq("parent_id", itemCat.getId());
            List<ItemCat> twoList = itemCatMapper.selectList(qw);
            //2.根据2级删3级
            for (ItemCat twoItemCat: twoList){
                qw.clear();
                qw.eq("parent_id", twoItemCat.getId());
                itemCatMapper.delete(qw);
                /*//3.删除当前2级,每次循环都要连接数据库,可以优化
                itemCatMapper.deleteById(twoItemCat.getId());*/
                ids.add(twoItemCat.getId());//将要删除的二级id存入集合
            }
            //3.一次性删除二级,不用在循环里面一个一个删除二级了
            itemCatMapper.deleteBatchIds(ids);
            //4.删除1级
            itemCatMapper.deleteById(itemCat.getId());
        }
    }

权限管理

数据统计

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值