【JAVA】黑马MybatisPlus 学习笔记【三】【拓展功能】

3.扩展功能

3.1.代码生成

在使用MybatisPlus以后,基础的MapperServicePO代码相对固定,重复编写也比较麻烦。因此MybatisPlus官方提供了代码生成器根据数据库表结构生成POMapperService等相关代码。只不过代码生成器同样要编码使用,也很麻烦。(也就是说,我要生成代码,还要编写一套代码,让这套代码去生成代码)
这里推荐大家使用一款MybatisPlus的插件,它可以基于图形化界面完成MybatisPlus的代码生成,非常简单。

3.1.1.安装插件

Ideasetting中的plugins市场中搜索并安装MyBatisPlus插件:
在这里插入图片描述
然后重启Idea即可使用。

3.1.2.使用

刚好数据库中还有一张address表尚未生成对应的实体和mapper等基础代码。我们利用插件生成一下。
首先需要配置数据库地址,在Idea顶部菜单中,找到other,选择Config Database
在这里插入图片描述
在弹出的窗口中填写数据库连接的基本信息:
在这里插入图片描述
点击OK保存。
然后再次点击Idea顶部菜单中的other,然后选择Code Generator:

在这里插入图片描述
在弹出的表单中填写信息:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
最终,代码自动生成到指定的位置。

3.2.静态工具

有的时候Service之间也会相互调用,为了避免出现循环依赖问题,MybatisPlus提供一个静态工具类:Db,其中的一些静态方法与IService中方法签名基本一致,也可以帮助我们实现CRUD功能:
在这里插入图片描述
由于Db 是静态的,无法通过泛型传递,只能通过传递字节码,得到类名

示例:

@Test
void testDbGet() {
    User user = Db.getById(1L, User.class);
    System.out.println(user);
}

@Test
void testDbList() {
    // 利用Db实现复杂条件查询
    List<User> list = Db.lambdaQuery(User.class)
            .like(User::getUsername, "o")
            .ge(User::getBalance, 1000)
            .list();
    list.forEach(System.out::println);
}

@Test
void testDbUpdate() {
    Db.lambdaUpdate(User.class)
            .set(User::getBalance, 2000)
            .eq(User::getUsername, "Rose");
}

在这里插入图片描述

案例一:改造根据id用户查询的接口,查询用户的同时返回用户收货地址列表

首先,我们要添加一个收货地址的VO对象:

package com.itheima.mp.domain.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel(description = "收货地址VO")
public class AddressVO{

    @ApiModelProperty("id")
    private Long id;

    @ApiModelProperty("用户ID")
    private Long userId;

    @ApiModelProperty("省")
    private String province;

    @ApiModelProperty("市")
    private String city;

    @ApiModelProperty("县/区")
    private String town;

    @ApiModelProperty("手机")
    private String mobile;

    @ApiModelProperty("详细地址")
    private String street;

    @ApiModelProperty("联系人")
    private String contact;

    @ApiModelProperty("是否是默认 1默认 0否")
    private Boolean isDefault;

    @ApiModelProperty("备注")
    private String notes;
}

然后,改造原来的UserVO,添加一个地址属性:
在这里插入图片描述

接下来,修改UserController中根据id查询用户的业务接口:

@GetMapping("/{id}")
@ApiOperation("根据id查询用户")
public UserVO queryUserById(@PathVariable("id") Long userId){
    // 基于自定义service方法查询
    return userService.queryUserAndAddressById(userId);
}

由于查询业务复杂,所以要在service层来实现。首先在IUserService中定义方法:

package com.itheima.mp.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;

public interface IUserService extends IService<User> {
  
    UserVO queryUserAndAddressById(Long userId);
}

然后,在UserServiceImpl中实现该方法:

@Override
    public UserVO queryUserAndAddressById(Long userId) {
        // 1.查询用户
        User user = getById(userId);
        if (user == null || user.getStatus() == 2){
            throw new RuntimeException("用户状态异常");
        }
            // 2.查询收货地址
        List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, userId).list();
        // 3.封装VO
        // 3.1 user的 po 转 vo
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        // 3.2 地址的po 转vo
        if(CollUtil.isNotEmpty(addresses)){
            userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));
        }

        return userVO;
    }

在查询地址时,我们采用了Db的静态方法,因此避免了注入AddressService,减少了循环依赖的风险。

再来实现一个功能:

案例二: 根据id批量查询用户,并查询出用户对应的所有地址

修改UserController中根据id查询用户的业务接口:

 @GetMapping
    @ApiOperation("根据id集合查询用户")
    public List<UserVO> queryUserByIds(@RequestParam("ids") List<Long> ids){
        return userService.queryUserAndAddressByIds(ids);
    }

service层。首先在IUserService中定义方法:

package com.itheima.mp.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;

public interface IUserService extends IService<User> {

      List<UserVO> queryUserAndAddressByIds(List<Long> ids);
}

然后,在UserServiceImpl中实现该方法:

 @Override
    public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
        // 1.查询用户
        List<User> users = listByIds(ids);
        if (CollUtil.isEmpty(users)) { // 如果为空 直接返回空列表
            return Collections.emptyList();
        }
        // 2.查询地址
        // 2.1. 获取用户id集合
        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        // 2.2. 根据用户id集合 查询地址
        List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();
        // 2.3.转地址VO
        List<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);
        // 2.4.用户地址集合 分组处理,一个用户对应一个地址集合,map结构
        Map<Long, List<AddressVO>> addressMap = new HashMap<>(0);
        if (CollUtil.isNotEmpty(addressVOList)) { // 根据用户id 进行分组
            addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
        }
        // 3.转VO返回
        ArrayList<UserVO> list = new ArrayList<>(users.size());
        for (User user : users) {
            //  3.1. 转换User 的 po 为 vo
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            list.add(userVO);
            //  3.2. 转换地址的VO
            userVO.setAddresses(addressMap.get(user.getId()));
        }
        return list;
    }

3.3.逻辑删除

对于一些比较重要的数据,我们往往会采用逻辑删除的方案,即:

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为true
  • 查询时过滤掉标记为true的数据
    一旦采用了逻辑删除,所有的查询和删除逻辑都要跟着变化,非常麻烦。

为了解决这个问题,MybatisPlus就添加了对逻辑删除的支持。

注意,只有MybatisPlus生成的SQL语句才支持自动的逻辑删除,自定义SQL需要自己手动处理逻辑删除。

例如,我们给address表添加一个逻辑删除字段:

alter table address add deleted bit default b'0' null comment '逻辑删除';

然后给Address实体添加deleted字段:
在这里插入图片描述
接下来,我们要在application.yml中配置逻辑删除字段:

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

在这里插入图片描述

测试:
首先,我们执行一个删除操作:

@Test
void testDeleteByLogic() {
    // 删除方法与以前没有区别
    addressService.removeById(59L);
}

方法与普通更新一模一样,但是底层的SQL逻辑变了:
在这里插入图片描述
执行结果如下图:
在这里插入图片描述

查询一下试试:

@Test
void testQuery() {
    List<Address> list = addressService.list();
    list.forEach(System.out::println);
}

会发现id59的确实没有查询出来,而且SQL中也对逻辑删除字段做了判断:

在这里插入图片描述

综上, 开启了逻辑删除功能以后,我们就可以像普通删除一样做CRUD,基本不用考虑代码逻辑问题。还是非常方便的。

注意:
逻辑删除本身也有自己的问题,比如:

  • 会导致数据库表垃圾数据越来越多,从而影响查询效率
  • SQL中全都需要对逻辑删除字段做判断,影响查询效率
    因此,我不太推荐采用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其它表的办法。

3.3.通用枚举

User类中有一个用户状态字段:
在这里插入图片描述
像这种字段我们一般会定义一个枚举,做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是int类型,对应的PO也是Integer因此业务操作时必须手动把枚举Integer转换,非常麻烦。
因此,MybatisPlus提供了一个处理枚举的类型转换器,可以帮我们把枚举类型与数据库类型自动转换。

3.3.1.定义枚举

我们定义一个用户状态的枚举:
在这里插入图片描述
代码如下:

package com.itheima.mp.enums;

import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;

@Getter
public enum UserStatus {
    NORMAL(1, "正常"),
    FREEZE(2, "冻结")
    ;
    private final int value;
    private final String desc;

    UserStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}

然后把User类中的status字段的数据类型由Integer改为UserStatus 类型:
在这里插入图片描述

要让MybatisPlus处理枚举与数据库类型自动转换,我们必须告诉MybatisPlus,枚举中的哪个字段的值作为数据库值。
MybatisPlus提供了@EnumValue注解来标记枚举属性:
在这里插入图片描述

3.3.2.配置枚举处理器

application.yaml文件中添加配置:

mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
3.3.3.测试
@Test
void testService() {
    List<User> list = userService.list();
    list.forEach(System.out::println);
}

最终,查询出的User类的status字段会是枚举类型:
在这里插入图片描述

同时,为了使页面查询结果也是枚举格式,我们需要修改UserVO中的status属性:
在这里插入图片描述
并且,在UserStatus枚举中通过@JsonValue注解标记JSON序列化时展示的字段:

在这里插入图片描述
最后,在页面查询,结果如下:
在这里插入图片描述

3.4.JSON类型处理器

数据库的user表中有一个info字段,是JSON类型:

在这里插入图片描述
格式像这样:

{"age": 20, "intro": "佛系青年", "gender": "male"}

而目前User实体类中却是String类型:
在这里插入图片描述
这样一来,我们要读取info中的属性时就非常不方便。如果要方便获取,info的类型最好是一个Map或者实体类

而一旦我们把info改为对象类型,就需要在写入数据库时手动转为String,再读取数据库时,手动转换为对象,这会非常麻烦。

因此MybatisPlus提供了很多特殊类型字段的类型处理器,解决特殊字段类型与数据库类型转换的问题。例如处理JSON就可以使用JacksonTypeHandler处理器。

接下来,我们就来看看这个处理器该如何使用。

3.4.1.定义实体

首先,我们定义一个单独实体类来与info字段的属性匹配:
在这里插入图片描述
代码如下:

package com.itheima.mp.domain.po;

import lombok.Data;

@Data
public class UserInfo {
    private Integer age;
    private String intro;
    private String gender;
}
3.4.2.使用类型处理器

接下来,将User类的info字段修改为UserInfo类型,并声明类型处理器

在这里插入图片描述
测试可以发现,所有数据都正确封装到UserInfo当中了:
在这里插入图片描述

在这里插入图片描述
同时,为了让页面返回的结果也以对象格式返回,我们要修改UserVO中的info字段:

在这里插入图片描述
此时,在页面查询结果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/270506.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【QT】可执行文件图标由png格式手动改为ico格式,Qt程序报错原因及解决方案

1问题说明&#xff1a; 在修改可执行文件图标时&#xff0c;由png格式手动改为ico格式&#xff0c;Qt程序会报错。 报错如下&#xff1a; 2解决办法&#xff1a; 登录网页 在线生成透明ICO图标——ICO图标制作&#xff0c;利用ico在线生成透明ICO图标 将生成的ico图标由favicon…

CSRF(Pikachu)

CSRF&#xff08;get&#xff09; 首先我们先登录账号 admin 密码是&#xff1b;123456 点击修改个人信息 用F12或者BP 抓包看看我们的url 那么构成的CSRF攻击payload为http://pikachu.shifa23.com/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sexboy&phonenum”手机…

如何申请云闪付支付接口?

随着移动支付的普及&#xff0c;越来越多的商家开始接受各种移动支付方式。而在众多移动支付工具中&#xff0c;云闪付支付接口因其安全、便捷的特点&#xff0c;成为了越来越多商家的首选。那么&#xff0c;如何申请云闪付支付接口呢&#xff1f;本文将为您详细介绍申请云闪付…

PaddleOCR 的使用,极简介绍

安装 参考github的官网就可以&#xff1a; github链接 简单的说&#xff0c;就是两句话&#xff1a; python3 -m pip install paddlepaddle-gpu -i https://mirror.baidu.com/pypi/simple pip install "paddleocr>2.0.1" # 推荐使用2.0.1版本 Python下的使用…

NAT协议的实现方式

在网络通信中&#xff0c;NAT协议&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;扮演着关键角色&#xff0c;允许内部网络与外部网络之间进行有效的通信。 实现内外网之间网络地址转换的过程中&#xff0c;NAT采用了不同的实现方式&#xff0c;…

FL Studio 21最新版本for mac 21.2.2.3470中文解锁版

FL Studio 21最新版本for mac 21.2.2.3470中文解锁版是最新强大的音乐制作工具。它可以与所有类型的音乐一起创作出令人惊叹的音乐。它提供了一个非常简单且用户友好的集成开发环境&#xff08;IDE&#xff09;来工作。这个完整的音乐工作站是由比利时公司 Image-Line 开发的。…

了解OAuth 2.0以及社交登录认证授权流程

1.前言 目前在写一个电商项目&#xff0c;可以通过手机号进行注册登录&#xff0c;为了方便用户使用本平台的系统&#xff0c;引入社交登录功能&#xff0c;这里使用的是gittee。 2.OAuth 2.0介绍 当谈到网络安全和身份验证时&#xff0c;OAuth 2.0&#xff08;开放授权 2.0&a…

AXI总线协议---关键信号波形图分析

写过程协议图 读过程协议图 读协议执行顺序图 写协议顺序图 单箭头表示两个信号谁先有效无所谓&#xff0c;双箭头表示必须要等到前一个信号有效才能将后面的信号有效 如何体现协议图中的通道理解 声明&#xff1a;以上图均采用AMBA总线文档图 写过程关键信号 主机 写地址—M…

MySQL集群架构搭建以及多数据源管理实战

MySQL集群架构搭建以及多数据源管理实战 ​ 数据库的分库分表操作&#xff0c;是互联网大型应用所需要面对的最核心的问题。因为数据往往是一个应用最核心的价值所在。但是&#xff0c;在最开始的时候&#xff0c;需要强调下&#xff0c;在实际应用中&#xff0c;对于数据库&a…

Keil5 5.38官方下载、安装及注册教程(详细版)

一、下载地址 官方C51版本下载地址&#xff1a;https://www.keil.com/demo/eval/c51.htm 官方ARM版本下载地址&#xff1a;https://www.keil.com/demo/eval/arm.htm 注&#xff1a;两个版本的安装教程一样 Keil注册机2032年&#xff1a; 链接&#xff1a;https://pan.baidu.…

虚拟机安装配置winServer2012

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《产品经理如何画泳道图&流程图》 ⛺️ 越努力 &#xff0c;越幸运 目录 1、准备工作&#xff1a; 2、VM虚拟机的安装 3、配置虚拟网络编辑器 3、安装系统 4、远程连接步骤 5、…

探索 HTTP 请求的世界:get 和 post 的奥秘(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

华为鸿蒙操作系统简介及系统架构分析(1)

本文部分内容参考&#xff1a; 鸿蒙系统学习笔记(一) 鸿蒙系统介绍 特此致谢。 一、简介及历史 1. 简介 鸿蒙操作系统&#xff08;HarmonyOS&#xff09;是华为公司研制的一款自主版权的操作系统。2019年8月9日&#xff0c;鸿蒙系统在华为开发者大会<HDC.2019>上正式…

AI大模型:未来科技的新篇章

目录 1AI大模型&#xff1a;未来科技的新篇章 2AI超越数学家攻克经典数学难题&#xff1b;非侵入式设备解码大脑思维 1AI大模型&#xff1a;未来科技的新篇章 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经成为了我们生活中不可或缺的一部分。而AI大…

图解机器学习神器:Scikit-Learn

算法进阶 ​​本文详解 Scikit-learn 工具库的用法&#xff0c;覆盖机器学习基础知识、SKLearn讲解、SKLearn三大核心API、SKLearn高级API等内容。 https://www.showmeai.tech/article-detail/203 我们在上一篇SKLearn入门与简单应用案例 [1] 里给大家讲到了 SKLearn 工具的基…

docker的一些思考

1.docker是啥&#xff1f; 2.镜像执行流程 3.一些疑惑和解答 1. 2.

【Jmeter、postman、python 三大主流技术如何操作数据库?】

前言 1、前言 只要是做测试工作的&#xff0c;必然会接触到数据库&#xff0c;数据库在工作中的主要应用场景包括但不限于以下&#xff1a; 功能测试中&#xff0c;涉及数据展示功能&#xff0c;需查库校验数据正确及完整性&#xff1b;例如商品搜索功能 自动化测试或性能测试…

Python中assert的用法

assert翻译成中文是“断言”的意思&#xff0c;用于判断一个表达式&#xff0c;在表达式条件为 false 的时候触发异常。断言可以在条件不满足程序运行的情况下直接返回错误&#xff0c;而不必等待程序运行后出现崩溃的情况&#xff0c;例如我们的代码只能在 Linux(Windows) 系统…

Pycharm的码云代码上传、下载步骤

前提&#xff1a;本地已经安装 git 安装包才行 注意注意&#xff1a;避免少出现 冲突&#xff1a;建议&#xff0c;先 pull &#xff0c;再 push。 下载&#xff1a; 上传&#xff1a;

〖Python网络爬虫实战㊹〗- JavaScript Hook 的用法

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;订阅本专栏前必读关于专栏〖Python网络爬虫实战〗转为付费专栏的订阅说明作者&#xff1…