MyBatisPlus 学习笔记
文章目录
- ` MyBatisPlus` 快速入门
- 第一步:引入 `MyBaitsPlus` 起步依赖
- 第二步:自定义的 `Mapper` 继承 `BaseMapper` 接口
- 新增相关
- 修改相关
- 删除相关
- 查询相关
- `Mp` 使用示例
- `MyBaitsPlus` 常见注解
- `MP` 实体类与数据库信息约定
- `Mp` 实体类与数据库信息约定不符合解决方法
- `MP` 自定义常见配置
- `MyBatisPlus` 条件构造器
- `AbstractWrapper` 公共方法
- 比较条件
- 模糊查询
- 范围条件
- 逻辑条件
- 注意事项
- 高级特性
- `QueryWrapper` 特有方法
- **`UpdateWrapper`** 特有方法
- `LambdaWrapper` 示例
- `MyBatisPlus` 自定义 `SQL`
- `MyBatisPlus` 的 `IService` 接口
- `IService` 接口使用
- 第一步:`Service` 接口实现 `IService<T>`
- 第二步:`Service` 实现类继承 `ServiceImpl<M extends BaseMapper<T>, T>`
- 第三步:编写 `SQL`
- `IService` 开发基础业务接口
- `UserController` 层
- `USerService` 接口
- `UserService` 实现类
- `UserMapper` 层
- `IService` 的 `Lambda` 查询与更改
- **常用条件方法**
- `Iservice` 中的 `LambdaQuery`
- `Iservice` 中的 `LambdaUpdate`
- `IService` 批量新增
- 普通 `for` 方案
- `Mp` 批量处理方案
- `Mp` 批量处理配合 `rewriteBatchedStatements=true`
- 新增数据
- 删除数据
- 修改数据
- 查询数据
- 统计与分页
- 链式操作(高级)
- `MyBatisPlus` 拓展功能
- `MP` 代码生成器
- 安装插件
- 使用
- `Mp` 静态工具
- 示例一
- 示例二
- `MP` 逻辑删除
- `Mp` 枚举处理器
- `Mp` 的 `Json` 处理器
- `Mp` 插件功能
- `Mp` 分页插件基本使用
- `Mp` 通用分页查询
- `MP` 通用分页实体改造
MyBatisPlus
快速入门
第一步:引入 MyBaitsPlus
起步依赖
第二步:自定义的 Mapper
继承 BaseMapper
接口
BaseMapper
接口提前定义好了一大堆增删改查的方法注意:泛型为对应实体类
新增相关
insert (T entity)
INSERT INTO {表名}
({字段1}, {字段2}, ...)
VALUES (#{entity.属性1}, #{entity.属性2}, ...)
修改相关
updateById(T entity)
UPDATE {表名}
SET {字段1}=#{entity.属性1}, {字段2}=#{entity.属性2}, ...
WHERE id = #{entity.id}
update(T entity, Wrapper<T> wrapper)
\
UPDATE {表名}
SET {字段1}=#{entity.属性1}, {字段2}=#{entity.属性2}, ...
WHERE {wrapper动态生成的条件}
删除相关
deleteById(Serializable id)
DELETE FROM {表名} WHERE id = #{id}
deleteByMap(Map<String, Object> map)
DELETE FROM {表名}
WHERE {map中的键值对条件}
-- 例如:name = 'John' AND age = 25
deleteBatchIds(Collection<?> ids)
DELETE FROM {表名}
WHERE id IN (id1, id2, id3...)
查询相关
selectById(Serializable id)
SELECT * FROM {表名} WHERE id = #{id}
selectBatchIds(Collection<?> ids)
SELECT * FROM {表名}
WHERE id IN (id1, id2, id3...)
selectOne(Wrapper<T> wrapper)
SELECT * FROM {表名}
WHERE {wrapper动态生成的条件}
LIMIT 1
selectList(Wrapper<T> wrapper)
SELECT * FROM {表名}
WHERE {wrapper动态生成的条件}
Mp
使用示例
//增@Testvoid testInsert() {User user = new User();//user.setId(5L);user.setUsername("ErGouZi");user.setPassword("123");user.setPhone("18688990013");user.setBalance(200);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}//查@Testvoid testQueryByIds() {List<User> users = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L));users.forEach(System.out::println);}//改@Testvoid testUpdateById() {User user = new User();user.setId(5L);user.setBalance(20000);userMapper.updateById(user);}//查@Testvoid testSelectById() {User user = userMapper.selectById(5L);System.out.println("user = " + user);} //删@Testvoid testDeleteUser() {userMapper.deleteById(5L);}
MyBaitsPlus
常见注解
MP
实体类与数据库信息约定
Mp
实体类与数据库信息约定不符合解决方法
实体类表名字段和数据库约定不符
- 加上对应的
@TableName
,@TableId
,TbaleField
主键自增长问题
没用
type
默认采用雪花算法数据库配置了
AUTO_INCREMENT
,实体类必须标注@TableId(type = IdType.AUTO)
数据库未配置
AUTO_INCREMENT
,可以选择INPUT
或者ASSIGN_ID
实体类
is
开头问题
- 实体类
isMarried
,数据库is_Married
符合映射规则。但是Java
中会忽略is
所以还是需要手动加上@TableField
字段名和数据库关键字冲突问题
- 比如下面的
order
。和数据库关键字冲突,所以笔记加上 ```飘号。实体类有,数据库没有的字段问题
- 使用
@TableField(exist = false)
MP
自定义常见配置
全局 id 配置配了,我们字段可以不用配置
type = ....
图中除了
type-aliases-package
其他都是默认值
MyBatisPlus
条件构造器
@Testvoid testQueryWrapper() {// 1.构建查询条件QueryWrapper<User> warpper = new QueryWrapper<User>().select("id", "username", "info", "balance").like("username", "o").ge("balance", 1000);// 2.查询userMapper.selectList(warpper);}
AbstractWrapper
公共方法
比较条件
eq(R column, Object val)
→column = val
ne(R column, Object val)
→column ≠ val
gt(R column, Object val)
→column > val
ge(R column, Object val)
→column ≥ val
lt(R column, Object val)
→column < val
le(R column, Object val)
→column ≤ val
模糊查询
like(R column, Object val)
→column LIKE '%val%'
notLike(R column, Object val)
→column NOT LIKE '%val%'
likeLeft(R column, Object val)
→column LIKE '%val
(左模糊)likeRight(R column, Object val)
→column LIKE 'val%'
(右模糊)
范围条件
between(R column, Object val1, Object val2)
→BETWEEN val1 AND val2
notBetween(R column, Object val1, Object val2)
→NOT BETWEEN
in(R column, Object... values)
→in(...)
逻辑条件
and()
→AND
连接多个条件or()
→OR
连接多个条件nested()
→ 嵌套条件
注意事项
- 链式调用:通过
.
连接多个条件(默认AND
逻辑) - 防 SQL 注入:优先使用
LambdaQueryWrapper
避免字段名硬编码 - 性能优化:避免在循环中频繁创建 Wrapper 对象
- 空值处理:
eq(null, val)
会忽略条件,需手动判空
高级特性
- 实体绑定:
setEntity(T entity)
自动从实体类提取条件 - 字段过滤:
columnsSqlInjectFilter()
防止非法字段注入 - Lambda 支持:
LambdaQueryWrapper
提供类型安全的字段引用(如User::getName
)
QueryWrapper
特有方法
-
select(String... columns)
→SELECT column1, column2
(指定返回字段) -
allEq(Map<R, V> params)
→ 批量等值匹配(如column1=val1 AND column2=val2
) -
…
@Testvoid testQueryWrapper() {// 1.构建查询条件QueryWrapper<User> warpper = new QueryWrapper<User>().select("id", "username", "info", "balance").like("username", "o").ge("balance", 1000);// 2.查询List<User> users = userMapper.selectList(warpper);users.forEach(System.out::println);}
@Testvoid testUpdateByQueryWrapper2() {// 1. 要更新的信息User user = new User();user.setBalance(2000);// 2. 更新的条件QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "jack");// 3. 执行更行int update = userMapper.update(user, wrapper);}
UpdateWrapper
特有方法
set(String column, Object value)
→SET column = value
setSql(String sql)
→ 直接拼接 SET 语句(如SET balance = balance + 100
)- …
@Testvoid testQueryWrapper2() {User user = new User();UpdateWrapper<User> wrapper = new UpdateWrapper<User>().set("balance", 2000).eq("username", "jack");int update = userMapper.update(user, wrapper);}
@Testvoid testUpdateWrapper() {User user = new User();UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200").in("id", 1, 2, 3);userMapper.update(user, wrapper);}
LambdaWrapper
示例
@Testvoid testLambdaQueryWrapper() {LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>().select(User::getId, User::getUsername, User::getInfo, User::getBalance).like(User::getUsername, "o").ge(User::getBalance, 1000);}
.select(User::getId, User::getUsername, User::getInfo, User::getBalance) 转为常规 Lambda 底层是 Functionnew Function<Long, User>() {@Overridepublic Long apply(User user) {return user.getId()}} .select(user -> user.getId(), user -> user.getUsername(), user -> user.getInfo(), user -> user.getBalance());
MyBatisPlus
自定义 SQL
很多公司数据库代码不能写在业务层。所以我们可以写好复杂条件,然后去数据库层拼接
@Testvoid testCustomSqlUpdate() {// 1.更新条件List<Long> ids = List.of(1L, 2L, 4L);int amount = 200;// 2.定义条件QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);// 3.调用自定义SQL方法userMapper.updateBalanceByIds(wrapper, amount);}
public interface UserMapper extends BaseMapper<User> {//这里条件必须叫 ewvoid updateBalanceByIds(@Param("ew") QueryWrapper<User> wrapper,@Param("amount") int amount);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mp.mapper.UserMapper"><update id="updateBalanceByIds"><!-- ${ew.customSQlSegment} 固定写法 拼接条件 这里是 in(...)--><!-- UPDATE tb_user SET balance = balance - ? WHERE (id IN (?,?,?))-->UPDATE tb_user SET balance = balance - #{amount} ${ew.customSQlSegment}</update></mapper>
MyBatisPlus
的 IService
接口
IService
接口使用
我们自己的接口需要继承
Iservice
接口,我们自己的实现类需要继承ServiceImpl
第一步:Service
接口实现 IService<T>
//IService<T> T 是实体类 entity
public interface IUserService extends IService<User> {}
第二步:Service
实现类继承 ServiceImpl<M extends BaseMapper<T>, T>
//ServiceImpl<Mapper的类型, 实体类entity>
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{}
第三步:编写 SQL
@SpringBootTest
class IUserServiceTest {@Autowiredprivate IUserService userservice;@Testvoid testSaveUser() {User user = new User();//user.setId(5L);user.setUsername("LiLei");user.setPassword("123");user.setPhone("18688990013");user.setBalance(200);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userservice.save(user);}@Testvoid testQuery() {List<User> users = userservice.listByIds(List.of(1L, 2L, 4L));users.forEach(System.out::println);}}
IService
开发基础业务接口
UserController
层
@Api(tags = "用户管理接口")
@RequestMapping("/users")
@RestController
//对一开始需要初始化的变量去做构造函数。配合注解
@RequiredArgsConstructor
public class UserController {//final 必须要初始化。这里建议在构造函数初始化, 自动注入private final IUserService userService;@ApiOperation("新增用户接口")@PostMappingpublic void saveUser(@RequestBody UserFormDTO userDTO) {// 1. 把DTO拷贝到PO 从哪里拷贝到哪里User user = BeanUtil.copyProperties(userDTO, User.class);// 2. 新增userService.save(user);}@ApiOperation("根据id删除用户接口")@DeleteMapping("{id}")public void deleteUserById(@ApiParam("用户id") @PathVariable("id") Integer id) {userService.removeById(id);}@ApiOperation("根据id查询用户接口")@GetMapping("{id}")public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Integer id) {// 1. 查询用户 POUser user = userService.getById(id);// 2. 把 PO 拷贝到 VOreturn BeanUtil.copyProperties(user, UserVO.class);}@ApiOperation("根据id批量查询用户接口")@GetMappingpublic List<UserVO> queryUserById(@ApiParam("用户id的集合") @RequestParam("ids") List<Long> ids) {// 1. 查询用户 POList<User> users = userService.listByIds(ids);// 2. 把 PO 拷贝到 VO// 把原始list 里面的对象拷贝到新的list 里面 转为别的类型return BeanUtil.copyToList(users, UserVO.class);}@ApiOperation("扣减用户余额接口")@DeleteMapping("{id}/deduction/{money}")public void deductBalance(@ApiParam("用户id") @PathVariable("id") Integer id,@ApiParam("扣减的金额") @PathVariable("money") Integer money) {userService.deductMoneyById(id, money);}
}
USerService
接口
public interface IUserService extends IService<User> {/*** 扣减用户余额* @param id* @param money*/void deductMoneyById(Integer id, Integer money);
}
UserService
实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{/*** 扣减用户余额* @param id* @param money*/@Overridepublic void deductMoneyById(Integer id, Integer money) {// 1.查询用户状态 自己调自己的方法User user = getById(id);// 2.校验用户状态if (user == null || user.getStatus() == 2) {throw new RuntimeException("状态异常");}// 3.校验余额是否充足if (user.getBalance() < money) {throw new RuntimeException("余额不足");}// Service 实现类可直接用 baseMapper 调用 Mapper 方法,无需手动注入。 因为 extends ServiceImpl// 4.扣减余额 update tb_user set balance = balance - ? where id = ?baseMapper.deductBalanceById(id, money);}}
UserMapper
层
public interface UserMapper extends BaseMapper<User> {@Update("update tb_user set balance = balance - #{money} where id = #{id}")void deductBalanceById(@Param("id") Integer id, @Param("money") Integer money);
}
IService
的 Lambda
查询与更改
常用条件方法
方法 | SQL 等价 | 说明 | 示例 |
---|---|---|---|
eq() | column = value | 等于 | .eq(User::getStatus, 1) |
ne() | column <> value | 不等于 | .ne(User::getRole, "admin") |
gt() | column > value | 大于 | .gt(User::getAge, 18) |
ge() | column >= value | 大于等于 | .ge(User::getScore, 60) |
lt() | column < value | 小于 | .lt(User::getBalance, 1000) |
le() | column <= value | 小于等于 | .le(User::getBalance, maxBalance) |
like() | column LIKE '%value%' | 模糊匹配 | .like(User::getName, "Tom") |
between() | column BETWEEN min AND max | 范围查询 | .between(User::getAge, 20, 30) |
in() | column IN (v1, v2...) | 包含在集合中 | .in(User::getId, idsList) |
Iservice
中的 LambdaQuery
动态查询
- 原始
MyBatis
MyBaitsPlus
改造
//就是动态SQL
@Overridepublic List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {List<User> users = lambdaQuery().like(name != null, User::getUsername, name)//第一个参数条件,第二个参数要查询的字段 username,第三个参数要传进来匹配的值 username 的值 .like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).between(minBalance != null && maxBalance != null, // 强制参数共存User::getBalance, minBalance, maxBalance) .list();//- .one():最多1个结果//- .list():返回集合结果//- .count():返回计数结果return users;}
Iservice
中的 LambdaUpdate
- 传统
xml
<update id="updateUserBalanceAndStatus">UPDATE tb_user<set>balance = #{remainBalance},<if test="remainBalance == 0">status = 2,</if></set>WHEREid = #{id}AND balance = #{user.balance} <!-- 乐观锁:基于旧值校验 -->
</update>
LambdaUpdate
改造
@Override@Transactionalpublic void deductMoneyById(Integer id, Integer money) {// 1.查询用户状态 自己调自己的方法User user = getById(id);// 2.校验用户状态if (user == null || user.getStatus() == 2) {throw new RuntimeException("状态异常");}// 3.校验余额是否充足if (user.getBalance() < money) {throw new RuntimeException("余额不足");}// Service 实现类可直接用 baseMapper 调用 Mapper 方法,无需手动注入。 因为 extends ServiceImpl// 4.扣减余额 update tb_user set balance = balance - ? where id = ?int remainBalance = user.getBalance() - money;lambdaUpdate().set(User::getBalance, remainBalance).set(remainBalance == 0, User::getStatus, 2).eq(User::getId, id).eq(User::getBalance, user.getBalance()) //乐观锁 用户的 balance = 查到的 balance 乐观锁校验.update();}
IService
批量新增
普通 for
方案
这种方案会发起 10000 次网络请求,
mysql
内部有执行 10000 次查询。效率最低,不推荐
@Testprivate User buildUser(int i) {User user = new User();user.setUsername("user_" + i);user.setPassword("123");user.setPhone("" + (186889900L + i));user.setBalance(2000);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());return user;}@Testvoid testSaveOneByOne() {long b = System.currentTimeMillis();for (int i = 0; i < 1000; i++) {userservice.save(buildUser(i));}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}
Mp
批量处理方案
这里我们每
1000
条数据就发送一次网络请求过去。然后MySQL
再逐条执行。效率还是差一点
@Testprivate User buildUser(int i) {User user = new User();user.setUsername("user_" + i);user.setPassword("123");user.setPhone("" + (186889900L + i));user.setBalance(2000);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());return user;}@Testvoid testSaveOneByOne() {long b = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {userservice.save(buildUser(i));}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}@Testvoid testSaveBatch() {// 我们每次批量插入 1000 条数据, 插入 100此机 10万条数据List<User> list = new ArrayList<>(1000);long b = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {// 2.添加一个 userlist.add(buildUser(i));// 3.每1000条批量插入一次 1000条数据之后打包到 mysql 。也就是 1000条数据只用一次网络请求if (i % 1000 == 0) {userservice.saveBatch(list);// 4.清空集合 准备下一批数据list.clear();}}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}
Mp
批量处理配合 rewriteBatchedStatements=true
这里我们每
1000
条数据就发送一次网络请求过去。然后将多态SQL
合并未一条MySQL
只执行一次。效率最高INSERT INTO user ( username, password, phone, info, balance, create_time, update_time ) VALUES (user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01), (user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01), (user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01), (user_4, 123, 18688190004, "", 2000, 2023-07-01, 2023-07-01);
- 配置文件
yaml
//配置rewriteBatchedStatements=true
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=truedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: Ting123321
- 代码
@Testprivate User buildUser(int i) {User user = new User();user.setUsername("user_" + i);user.setPassword("123");user.setPhone("" + (186889900L + i));user.setBalance(2000);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());return user;}@Testvoid testSaveOneByOne() {long b = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {userservice.save(buildUser(i));}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}@Testvoid testSaveBatch() {// 我们每次批量插入 1000 条数据, 插入 100此机 10万条数据List<User> list = new ArrayList<>(1000);long b = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {// 2.添加一个 userlist.add(buildUser(i));// 3.每1000条批量插入一次 1000条数据之后打包到 mysql 。也就是 1000条数据只用一次网络请求if (i % 1000 == 0) {userservice.saveBatch(list);// 4.清空集合 准备下一批数据list.clear();}}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}
新增数据
save(T)
: 新增单条数据 → 返回操作是否成功 (boolean
)saveBatch(Collection<T>)
: 批量新增 → 返回是否成功saveBatch(Collection<T>, int batchSize)
: 指定批次大小的批量新增
删除数据
removeById(Serializable id)
: 根据 ID 删除单条数据removeByMap(Map条件)
: 根据 Map 条件删除removeByIds(Collection<?> ids)
: 批量删除(根据 ID 集合)removeBatchByIds(Collection<?>, int batchSize)
: 指定批次大小的批量删除
修改数据
updateById(T)
: 根据 ID 修改单条数据 → 返回是否成功saveOrUpdate(T)
: 存在则更新,否则新增(单条)saveOrUpdateBatch(Collection<T>)
: 批量新增或更新
查询数据
getById(Serializable id)
: 根据 ID 查询单条 → 返回实体 (T
)getOne(Wrapper<T>条件)
: 根据条件查询单条 → 返回实体listByIds(Collection<?> ids)
: 根据 ID 集合批量查询 → 返回列表 (List<T>
)listByMap(Map条件)
: 根据 Map 条件查询 → 返回列表
统计与分页
count()
: 统计总数据量 → 返回long
count(Wrapper<T>条件)
: 根据条件统计 → 返回long
page()
: 分页查询(需配合分页参数使用)
链式操作(高级)
lambdaQuery()
: 链式 Lambda 条件查询(如lambdaQuery().eq(...).list()
)lambdaUpdate()
: 链式 Lambda 条件更新(如lambdaUpdate().set(...).eq(...)
)
MyBatisPlus
拓展功能
MP
代码生成器
在使用
MybatisPlus
以后,基础的Mapper
、Service
、PO
代码相对固定,重复编写也比较麻烦。因此MybatisPlus
官方提供了代码生成器根据数据库表结构生成PO
、Mapper
、Service
等相关代码。只不过代码生成器同样要编码使用,也很麻烦。
安装插件
使用
- 首先需要配置配置数据库地址
- 然后选择
Code Generator
,填写信息
Mp
静态工具
示例一
需求:改造根据
id
用户查询的接口,查询用户的同时返回用户收货地址列表
- 收货地址
VO
@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;
}
- 用户
VO
- 注意添加一个地址属性
List<AddressVO> addresses
- 注意添加一个地址属性
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {@ApiModelProperty("用户id")private Long id;@ApiModelProperty("用户名")private String username;@ApiModelProperty("详细信息")private String info;@ApiModelProperty("使用状态(1正常 2冻结)")private Integer status;@ApiModelProperty("账户余额")private Integer balance;//对多关系。@ApiModelProperty("用户的收获地址")private List<AddressVO> addresses;
}
UserController
层
@ApiOperation("根据id查询用户接口")@GetMapping("{id}")public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Integer id) {return userService.queryUserAndAddressById(id);}
UserServiceImpl
层
@Overridepublic UserVO queryUserAndAddressById(Integer id) {// 1.查询用户User user = getById(id);if (user == null || user.getStatus() == 2) {throw new RuntimeException("用户状态异常!");}// 2.查询地址List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();// 3.封装 VO// 3.1.转User的PO为VOUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);// 3.2.转地址VOif(CollUtil.isNotEmpty(addresses)) {List<AddressVO> addressVos = BeanUtil.copyToList(addresses, AddressVO.class);userVO.setAddresses(addressVos);}return userVO;}
示例二
根据
id
批量查询用户,并查询出用户对应的所有地址
- 收货地址
VO
@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;
}
- 用户
VO
- 注意添加一个地址属性
List<AddressVO> addresses
- 注意添加一个地址属性
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {@ApiModelProperty("用户id")private Long id;@ApiModelProperty("用户名")private String username;@ApiModelProperty("详细信息")private String info;@ApiModelProperty("使用状态(1正常 2冻结)")private Integer status;@ApiModelProperty("账户余额")private Integer balance;//对多关系。@ApiModelProperty("用户的收获地址")private List<AddressVO> addresses;
}
UserController
层
@ApiOperation("根据id查询用户接口")@GetMapping("{id}")public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Integer id) {return userService.queryUserAndAddressById(id);}
UserServiceImpl
层
@Overridepublic 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.转换地址VOList<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);// 2.4.梳理地址集合, 分类整理, 相同用户的放入一个集合中Map<Long, List<AddressVO>> addressMap = new HashMap<>(0);if (CollUtil.isNotEmpty(addressVOList)) {addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));}// 3.转换VO返回List<UserVO> list = new ArrayList<>(users.size());for (User user : users) {// 3.1.转User的PO为VOUserVO vo = BeanUtil.copyProperties(user, UserVO.class);list.add(vo);// 3.2.转换Address的PO为VOvo.setAddresses(addressMap.get(user.getId()));}return list;}
MP
逻辑删除
或者直接在字段上面标注 @TableLogic
注解
- 配置逻辑删除字段
mybatis-plus:mapper-locations: classpath*:mapper/*.xmlglobal-config:db-config:id-type: autologic-delete-field: deleted #配置逻辑删除字段
- 正常操作就进行逻辑删除
@SpringBootTest
class IAddressServiceTest {@Autowiredprivate IAddressService addressService;@Testvoid testLogicDelete() {// 1. 删除addressService.removeById(59L);// 2. 查询Address adress = addressService.getById(59L);System.out.println("address = " + adress);}
}
Mp
枚举处理器
像
status
这种字段我们一般会定义一个枚举,做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是int
类型,对应的PO
也是Integer
。因此业务操作时必须手动把枚举
与Integer
转换,非常麻烦。因此,MybatisPlus
提供了一个处理枚举的类型转换器,可以帮我们把枚举类型与数据库类型自动转换。@EnumValue
表示把哪个字段往数据库写
- 定义枚举类
@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 POJO
枚举字段为枚举类型
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {@ApiModelProperty("用户id")private Long id;@ApiModelProperty("用户名")private String username;@ApiModelProperty("详细信息")private String info;//这里改为枚举类型@ApiModelProperty("使用状态(1正常 2冻结)")private UserStatus status;@ApiModelProperty("账户余额")private Integer balance;@ApiModelProperty("用户的收获地址")private List<AddressVO> addresses;
}
- 枚举类中用
EnumValue
标记哪个字段的值作为数据库的值
public enum UserStatus {NORMAL(1, "正常"),FROZEN(2, "异常");@EnumValueprivate final int value;private final String desc;UserStatus(int value, String desc) {this.value = value;this.desc = desc;}
}
- 配置枚举处理器
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
- 枚举类用
@JsonValue
标记JSON
序列化时展示的字段- 如果没标记默认用枚举值
public enum UserStatus {NORMAL(1, "正常"),FROZEN(2, "异常");@EnumValueprivate final int value;@JsonValueprivate final String desc;UserStatus(int value, String desc) {this.value = value;this.desc = desc;}
}
Mp
的 Json
处理器
我们数据库
User
表中有一个info
字段,是JSON
类型吗,而对应User
实体类的字段确实String
类型,这样一来info
属性要转来转去很麻烦。所以可以用Mp
中的JacksonTypeHandler
处理器自动处理
- 定义一个单独的实体类和
Info
字段匹配
@Data
@NoArgsConstructor
//生成一个静态工厂方法调用全参构造
@AllArgsConstructor(staticName = "of")
public class UserInfo {private Integer age;private String intro;private String gender;
}
- 在
User
实体类修改字段类型为UserInfo
类型,并声明类型处理器,同时声明自动映射
@Data
//声明自动映射
@TableName(value = "tb_user", autoResultMap = true)
public class User {/*** 用户id*/@TableId(type = IdType.AUTO)private Long id;/*** 用户名*/private String username;/*** 密码*/private String password;/*** 注册手机号*/private String phone;/*** 详细信息*///声明类型处理器@TableField(typeHandler = JacksonTypeHandler.class)private UserInfo info;/*** 使用状态(1正常 2冻结)*/private UserStatus status;/*** 账户余额*/private Integer balance;/*** 创建时间*/private LocalDateTime createTime;/*** 更新时间*/private LocalDateTime updateTime;
}
- 测试
@Testvoid testInsert() {User user = new User();//user.setId(5L);user.setUsername("ErGouZi");user.setPassword("123");user.setPhone("18688990013");user.setBalance(200);//这里正常插入数据就行,自动转为 JSON 类型user.setInfo(UserInfo.of(24, "英文老师", "female"));user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}
Mp
插件功能
Mp
分页插件基本使用
- 新建配置类,配置分页插件
@Configuration
public class MyBatisConfig {@Beanpublic MybatisPlusInterceptor myPlusInterceptor() {// 初始化核心插件MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 1.创建分页插件PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);// 1.1配置分页上限paginationInnerInterceptor.setMaxLimit(1000L);// 2.添加分页插件interceptor.addInnerInterceptor(paginationInnerInterceptor);//如果要添加其他插件,就先创建出来然后add进去就行return interceptor;}
}
- 开始分页查询
@Testvoid testPageQuery() {int pageNo = 1, pageSize = 2;// 1.准备分页条件Page<User> page = Page.of(pageNo, pageSize);// 1.1. 添加排序条件:按照 balance 升序排序,相同再按照 id 升序排序page.addOrder(new OrderItem("balance", true));page.addOrder(new OrderItem("id", true));// 2.开始分页查询Page<User> p = userservice.page(page);// 3.解析long total = p.getTotal();System.out.println("总记录数:" + total);long pages = p.getPages();System.out.println("总页数:" + pages);List<User> records = p.getRecords();records.forEach(System.out::println);}
Mp
通用分页查询
UserQuery
:分页查询条件的实体,包含分页、排序参数、过滤条件PageDTO
:分页结果实体,包含总条数、总页数、当前页数据UserVO
:用户页面视图实体
- 创建
PageQuery
分页条件类,并让UserQuery
继承pageNo
:页码pageSize
:每页数据条数sortBy
:排序字段isAsc
:是否升序
其中缺少的仅仅是分页条件,而分页条件不仅仅用户分页查询需要,以后其它业务也都有分页查询的需求。因此建议将分页查询条件单独定义为一个
PageQuery
实体
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {@ApiModelProperty("页码")private Long pageNo;@ApiModelProperty("页码")private Long pageSize;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc;
}
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(description = "用户查询条件实体")
public class UserQuery extends PageQuery {@ApiModelProperty("用户名关键字")private String name;@ApiModelProperty("用户状态:1-正常,2-冻结")private Integer status;@ApiModelProperty("余额最小值")private Integer minBalance;@ApiModelProperty("余额最大值")private Integer maxBalance;
}
UserVO
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {@ApiModelProperty("用户id")private Long id;@ApiModelProperty("用户名")private String username;@ApiModelProperty("详细信息")private UserInfo info;@ApiModelProperty("使用状态(1正常 2冻结)")private UserStatus status;@ApiModelProperty("账户余额")private Integer balance;@ApiModelProperty("用户的收获地址")private List<AddressVO> addresses;
}
- 分页实体
PageDTO
@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {@ApiModelProperty("总条数")private Long total;@ApiModelProperty("总页数")private Long pages;@ApiModelProperty("集合")private List<T> list;
}
Controller
层
@ApiOperation("根据复杂条件分页查询接口")@GetMapping("/page")public PageDTO<UserVO> queryUsersPage(UserQuery query) {return userService.queryUserPage(query);}
UserServiceImpl
层
/*** 根据复杂条件分页查询接口* @param query* @return*/@Overridepublic PageDTO<UserVO> queryUserPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();// 1.构建查询条件// 1.1.分页条件Page<User> page = Page.of(query.getPageNum(), query.getPageSize());if (StrUtil.isNotBlank(query.getSortBy())) {//不为空page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));} else {//为空, 默认按照更新时间排序page.addOrder(new OrderItem("update_time", false));}// 2.分页查询lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);// 3.封装VO结果PageDTO<UserVO> dto = new PageDTO<>();// 3.1. 设置总条数dto.setTotal(page.getTotal());// 3.2. 设置总页数dto.setPages(page.getPages());// 3.3. 设置当前页数据List<User> records = page.getRecords();if (CollUtil.isEmpty(records)) {dto.setList(Collections.emptyList());return dto;}// 3.4 拷贝 user 的VOList<UserVO> vos = BeanUtil.copyToList(records, UserVO.class);dto.setList(vos);// 4.返回return dto;}
MP
通用分页实体改造
PageQuery
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {@ApiModelProperty("页码")private Integer pageNum = 1;@ApiModelProperty("每页条数")private Integer pageSize = 5;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc = true;public <T> Page<T> toMpPage(OrderItem ... items) {// 1.分页条件Page<T> page = Page.of(pageNum, pageSize);// 2.排序条件if (StrUtil.isNotBlank(sortBy)) {//不为空page.addOrder(new OrderItem(sortBy, isAsc));} else if(items != null){//为空, 默认按照更新时间排序page.addOrder(items);}return page;}public <T> Page<T> toMoPage(String defaultSortBy, Boolean defaultAsc) {return toMpPage(new OrderItem("create_time", defaultAsc));}public <T> Page<T> toMoPageDefaultSortByCreateTime() {return toMpPage(new OrderItem("create_time", false));}public <T> Page<T> toMoPageDefaultSortByUpdateTime() {return toMpPage(new OrderItem("update_time", false));}}
PageDTO
@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {@ApiModelProperty("总条数")private Long total;@ApiModelProperty("总页数")private Long pages;@ApiModelProperty("集合")private List<T> list;public static <PO, VO> PageDTO<VO> of(Page<PO> p, Function<PO, VO> convertor) {PageDTO<VO> dto = new PageDTO<>();// 3.1. 设置总条数dto.setTotal(p.getTotal());// 3.2. 设置总页数dto.setPages(p.getPages());// 3.3. 设置当前页数据List<PO> records = p.getRecords();if (CollUtil.isEmpty(records)) {dto.setList(Collections.emptyList());return dto;}// 4 拷贝 user 的VOdto.setList(records.stream().map(convertor).collect(Collectors.toList()));// 4.返回return dto;}}
UserServiceImpl
@Overridepublic PageDTO<UserVO> queryUserPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();// 1.构建查询条件Page<User> page = query.toMoPageDefaultSortByUpdateTime();// 2.分页查询Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);// 3.封装 VO 结果return PageDTO.of(p, user -> {// 1.拷贝基础属性UserVO vo = BeanUtil.copyProperties(user, UserVO.class);// 2.处理特殊逻辑vo.setUsername(user.getUsername().substring(0, vo.getUsername().length() -2) + "**");return vo;});}
相关文章:
MyBatisPlus 学习笔记
文章目录 MyBatisPlus 快速入门第一步:引入 MyBaitsPlus 起步依赖第二步:自定义的 Mapper 继承 BaseMapper 接口新增相关修改相关删除相关查询相关 Mp 使用示例 MyBaitsPlus 常见注解MP 实体类与数据库信息约定Mp 实体类与数据库信息约定不符合解决方法…...
Profibus DP主站如何转Modbus TCP?
Profibus DP主站如何转Modbus TCP? 在现代工业自动化系统中,设备之间的互联互通至关重要。Profibus DP 和 Modbus TCP 是两种常见的通信协议,分别应用于不同的场景。为了实现这两种协议的相互转换,Profibus DP主站转Modbus TCP网…...
尚硅谷Java第 4、5 章IDEA,数组
第 4 章:IDEA的使用 第 5 章:数组 5.1 数组的概述 数组(Array):就可以理解为多个数据的组合。 程序中的容器:数组、集合框架(List、Set、Map)。 数组中的概念: 数组名 下标(或索…...
一些简单但常用的算法记录(python)
1、计算1-2020间的素数个数 def is_composite(num):if num < 1:return False# 从 2 开始到 num 的平方根进行遍历for i in range(2, int(num**0.5) 1):if num % i 0:return Truereturn Falsecnt 0 for num in range(1, 2021):if is_composite(num):cnt 1print(cnt)2、 …...
基于Docker容器的CICD项目Jenkins/gitlab/harbor/Maven实战
一、企业业务代码发布方式 1.1 传统方式 以物理机或虚拟机为颗粒度部署部署环境比较复杂,需要有先进的自动化运维手段出现问题后重新部署成本大,一般采用集群方式部署部署后以静态方式展现 1.2 容器化方式 以容器为颗粒度部署部署方式简单࿰…...
高并发秒杀系统设计:关键技术解析与典型陷阱规避
电商、在线票务等众多互联网业务场景中,高并发秒杀活动屡见不鲜。这类活动往往在短时间内会涌入海量的用户请求,对系统架构的性能、稳定性和可用性提出了极高的挑战。曾经,高并发秒杀架构设计让许多开发者望而生畏,然而࿰…...
(十四)安卓开发中的RecyclerView详解
在安卓开发中,RecyclerView 是一个功能强大且灵活的 UI 组件,用于高效地显示大量数据集合,如列表、网格或瀑布流。它是传统 ListView 和 GridView 的现代替代品,提供了更高的性能优化和自定义能力。RecyclerView 的核心优势在于其…...
如何设置Ubuntu服务器版防火墙
在Ubuntu服务器中,默认使用 ufw(Uncomplicated Firewall)作为防火墙管理工具。它是对iptables的简化封装,适合快速配置防火墙规则。以下是设置防火墙的详细步骤: 1. 安装与启用 ufw 安装(通常已预装&…...
根文件系统(rootfs) 制作方法(BusyBox、Buildroot、Yocto、Ubuntu Base)
以下是关于 根文件系统(rootfs) 制作的四种主流方法(BusyBox、Buildroot、Yocto、Ubuntu Base)的详细教程与对比分析,结合不同场景的需求提供具体实现步骤和关键要点。 1. BusyBox 制作 rootfs 核心特点 轻量级&…...
SAP软件FICO各种财务账期的功能用途介绍
FI会计账期 一般财务账期总账期间的控制是仅开启当前一个期间,如果月结期间应同时开启结账期间和下一期间两个期间,结账完成需立即关闭已完成结账的期间,避免凭证过账日期误记账。 设置事务码:OB52或 S_ALR_87003642 备注&#…...
蓝桥杯C++组部分填空题
P1508 - [蓝桥杯2020初赛] 门牌制作 - New Online Judge #include<bits/stdc.h> using namespace std;int main() {int res 0;for(int i 1; i < 2020; i){int num i;while(num){if(num % 10 2) res;num/10;}}cout<<res;return 0; } 624 P1509 - [蓝桥杯20…...
内联inline
一、什么是 inline? inline 的本意是: 建议编译器将函数调用处展开成函数体代码,省去函数调用的开销。 inline int square(int x) { return x * x; } 当你调用 square(5) 时,编译器可能会将其替换成 5 * 5,从而避免…...
【models】Transformer 之 各种 Attention 原理和实现
Transformer 之 各种 Attention 原理和实现 本文将介绍Transformer 中常见的Attention的原理和实现,其中包括: Self Attention、Spatial Attention、Temporal Attention、Cross Attention、Grouped Attention、Tensor Product Attention、FlashAttentio…...
基于JavaAPIforKml实现Kml 2.2版本的全量解析实践-以两步路网站为例
目录 前言 一、关于两步路网站 1、相关功能 2、数据结构介绍 二、JAK的集成与实现 1、JAK类图简介 2、解析最外层数据 3、解析扩展元数据和样式 4、递归循环解析Feature 5、解析具体的数据 三、结论 前言 随着地理信息技术的快速发展,地理空间数据的共享…...
Ubuntu搭建Pytorch环境
Ubuntu搭建Pytorch环境 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 Ubuntu搭建Pytorch环境前言一、Anaconda二、Cuda1.安装流程2、环境变量&#…...
Kingbase逻辑备份与恢复标准化实施文档
背景 文章背景 本文结合实际运维经验,围绕 Kingbase 数据库在逻辑层面的备份与恢复方法进行系统性梳理,旨在为运维人员和数据库管理员提供一套清晰、高效、可落地的操作指引,提升数据库系统的可靠性与容灾能力。 第一部分 逻辑部分 1.1 全…...
二分查找5:852. 山脉数组的峰顶索引
链接:852. 山脉数组的峰顶索引 - 力扣(LeetCode) 题解: 事实证明,二分查找不局限于有序数组,非有序的数组也同样适用 二分查找主要思想在于二段性,即将数组分为两段。本体就可以将数组分为ar…...
解决opencv中文路径问题
见cv_imread函数和cv_imwrite函数 import cv2 import os import matplotlib.pyplot as plt from paddleocr import PaddleOCR, draw_ocr import numpy as np import urllib.parse # Add this import statementfrom txt_get import ImageTextExtractor# 初始化OCR,…...
Redis简介及其在Unity中的应用
一、什么是Redis? Redis(Remote Dictionary Server) 是一个开源的高性能 内存数据结构存储系统,常被用于 缓存、消息队列、排行榜、会话管理、实时分析 等。 ✅ Redis特点 基于内存,读写速度极快支持多种数据结构:String、List、Hash、Set、Sorted Set支持持久化,可将…...
Python实现批量插入PostgreSQL数据库的脚本分享
背景 上个月排查一个 Bug ,需要采集一张 PostgreSQL 的大表,测试时需要造数据。Python 比 Java 方便多了,所以用 Python写了一个批量插入 PostgreSQL 表的简单脚本。本文分享这个脚本,很简单的,就是利用 psycopg2 的 …...
一键精准采集单网页,告别手动复制粘贴
浏览某个网页时,想抓取其内容,有没有工具能避免自己手动逐个复制粘贴? 推荐使用单网页一键采集功能,可自动提取网页内容并整理成结构化数据(包括标题、正文、作者、日期、分类、标签、描述和原文网址链接等关键信息&am…...
vue入门:单文件组件数据双向绑定
文章目录 单文件组件介绍安装创建项目构建单文件组件 数据双向绑定Vue虚拟DOM的作用Vue中key属性的作用 单文件组件 介绍 单文件组件API使用文件扩展名为 .vue 的来构建组件ECMAScript 6 API 安装 Vue CLI 构建Vue -- 安装vue/cli npm install -g vue/cli-- 升级Vue CLI 包…...
接听电话,手机靠近耳朵后拿开,挂断电话,设备自动锁屏
目录 一、问题分析/需求分析 二、解决方案 一、问题分析/需求分析 先说一下大致流程: 首先是打电话过程会启动PROXIMITY(接近光传感器)用于监听手机是否到耳边,当手机到耳边时进行灭屏处理,灭屏过程中会调用到锁屏,所以最终会导致锁屏 详细流程分析: 首先根据日志看…...
代码随想录第15天:(二叉树)
一、二叉搜索树的最小绝对差(Leetcode 530) 思路1 :中序遍历将二叉树转化为有序数组,然后暴力求解。 class Solution:def __init__(self):# 初始化一个空的列表,用于保存树的节点值self.vec []def traversal(self, r…...
Matlab 汽车ABS的PID控制
1、内容简介 Matlab 199-汽车ABS的PID控制 可以交流、咨询、答疑 2、内容说明 略 摘 要 : 在 simulink 环境下对汽车防抱死制动系统进行数学建模 , 采用基于…...
若依前后端分离版之使用Swagger
记录一下使用若依前后端分离版本中,怎么使用Swagger,以帮助初学者快速入手。 1.运行项目并查看Swagger 这里自己下载项目代码,在编译器中打开运行。这个过程跳过,我们进入系统后台界面。 在系统工具、系统接口中打开Swagger页面 点击test-controller和Schemas,可展开相…...
入侵检测snort功能概述
1. 数据包嗅探与日志记录 网络流量监控:实时捕获和分析网络数据包(支持以太网、无线等)。 日志记录:将数据包以二进制格式(pcap)或文本格式存储,供后续分析。 2. 协议分析与解码 深度协议解析…...
Notepad++安装Markdown实时预览插件
具体操作 打开notepad -> 插件 -> 插件管理 -> 可用 -> “Markdown Panel” -> 安装,安装完成后工具栏点击"Markdown Panel"按钮。 注意:由于网络等原因可能安装失败 导致工具栏没出现""Markdown Panel"按钮&am…...
Swift 实现 LeetCode 254:因子组合问题的递归解法全解析
文章目录 摘要描述示例: 题解答案(Swift 实现)题解代码分析核心思路:举个例子: 示例测试及结果时间复杂度分析空间复杂度分析现实应用场景结合总结 摘要 这篇文章我们来聊聊 LeetCode 第 254 题 ——「因子的组合」。…...
Matlab 传感器加速度数据计算位移
1、内容简介 Matlab 195-传感器加速度数据计算位移 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略...
Ubuntu虚拟机连不上网
桥接 虚拟机Ubuntu系统必须能连接到外网,不然不能更新软件安装包 配置虚拟机网络(关机或者挂起状态) 第一步1.重启虚拟机网络编辑器(还原配置) 第二步2.重启虚拟机网络适配器(移除再添加) 启…...
大模型论文:Language Models are Unsupervised Multitask Learners(GPT2)
大模型论文:Language Models are Unsupervised Multitask Learners(GPT2) 文章地址:https://storage.prod.researchhub.com/uploads/papers/2020/06/01/language-models.pdf 摘要 自然语言处理任务,例如问答、机器翻译、阅读理解和摘要&am…...
大模型本地部署系列(3) Ollama部署QwQ[阿里云通义千问]
大家好,我是AI研究者, 今天教大家部署 一个阿里云通义千问大模型。 QwQ大模型简介 QwQ是由阿里云通义千问(Qwen)团队推出的开源推理大模型,专注于提升AI在数学、编程和复杂逻辑推理方面的能力。其核心特点包括&#x…...
WPF ObjectDataProvider
在 WPF(Windows Presentation Foundation)中,ObjectDataProvider 是一个非常有用的类,用于将非 UI 数据对象(如业务逻辑类或服务类)与 XAML 绑定集成。它允许在 XAML 中直接调用方法、访问属性或实例化对象,而无需编写额外的代码。以下是关于 ObjectDataProvider 的详细…...
《Vue Router实战教程》12.不同的历史记录模式
欢迎观看《Vue Router 实战(第4版)》视频课程 不同的历史记录模式 在创建路由器实例时,history 配置允许我们在不同的历史模式中进行选择。 Hash 模式 hash 模式是用 createWebHashHistory() 创建的: import { createRouter,…...
Dify什么?Dify 零门槛打造专属 AI 应用
Dify 是一个专注于简化大语言模型(LLM)应用开发的开源平台,旨在帮助用户通过可视化界面和模块化工具快速构建、部署和管理 AI 驱动的应用程序。以下是其核心特点: 主要功能 可视化编排 提供直观的界面,无需深入编码即…...
【Javascript】在canvas中加载shader着色器的方法(开箱即用)
功能简介 可以播放,暂停shader代码,可以在js中配置shader参数(下面案例列举了所有可用参数形式)缺点 这个是固定机位,没有自定义顶点着色器部分的功能,有需要可直接在class中改,或者修改后调用…...
华为华三模拟器解决兼容问题Win11 24H2 现在使用ENSP的问题解决了
一、Win11 24H2 现在使用ENSP的问题解决了 这个Win11 的 24H2不能使用ENSP的问题已经困扰我们很久了,在之前的文章中,我们也有说明这个问题 之前ENSP肯定启动会报错40 当时还建议大家先不要更新到win11的24H2版本,现在终于迎来了更新&#…...
五、用例篇
Bug等级:崩溃、严重、一般、次要 bug的生命周期 面试高频考题:跟开发产生争执怎么办? (1)反思自己,是不是bug描述写的不清楚 (2)站在用户思考问题,反问开发人员:“如果你是用户,你能接受这样…...
Mysql中的数据类型和语句概述
Mysql中的数据类型 数值类 整数:int,四个字节构成 浮点型:float单精度浮点数,四个字节,double双精度浮点数,八个字节,decimal用于高精度计算,尤其是在金融领域。decimalÿ…...
Vue3连接MQTT作为客户端
先下载依赖 npx --yes --registry https://registry.npmmirror.com npm install mqtt 在src的api创建 mes.js // 导入axios import axios from axios;// 定义一个变量,记录公共的前缀, baseURL const baseURL http://localhost:8080; const instance axios.create({ base…...
VLC快速制作rtsp流媒体服务器
1.安装vlc media player工具 2.打开后点击菜单 媒体->流 3.添加mp4视频,选择串流 4.选择 下一个 5.新目标选择 RTSP,点击添加按钮 6.端口和路径随便填写,如果推流失败就换个端口。一路操作下去 7.点击 流 按钮后,就可以看到下图…...
24FIC
一,赛前准备 检材密码:2024Fic杭州Powered~by~HL! 案情简介: 2024年4月,卢某报案至警方,声称自己疑似遭受了“杀猪盘”诈骗,大量钱财被骗走。卢某透露,在与某公司交流过程中结识了员工李某。李某…...
P3367 【模板】并查集
题目链接:点击进入 题目 思路 代码(路径压缩) #include <bits/stdc.h> using namespace std; const int maxn 1e6 10;int n,m,fa[maxn];int find(int x) {if(xfa[x]) return x;else return fa[x]find(fa[x]); }int unions(int x,…...
【leetcode hot 100 300】最长递增子序列
错误解法:在每次更新db[i]时,如果当前nums[i]>nums[i-1]就db[i-1]1,否则db[i-1] class Solution {public int lengthOfLIS(int[] nums) {int n nums.length;int[] db new int[n]; // db[i]表示到i的最长严格递增子序列的长度db[0] 1;f…...
jwt.io学习
jwt.io 是一个专门用于 JSON Web Token(JWT)相关操作和学习的网站,地址是:JSON Web Tokens - jwt.io具有以下主要功能: JWT 解码:能够将 JWT 令牌进行解码,展示出令牌中包含的各个部分…...
MySQL 优化方案大全
一、数据库设计优化 1. 表结构设计 合理选择字段类型: 使用最小满足需求的类型(如TINYINT代替INT)字符串类型优先VARCHAR,固定长度用CHAR 时间类型用TIMESTAMP(4字节)或DATETIME(8字节…...
题目 2701: 蓝桥杯2022年第十三届决赛真题-取模(C/C++/Java组)
题目 2701: 蓝桥杯2022年第十三届决赛真题-取模(C/C/Java组) 时间限制: 3s 内存限制: 512MB 提交: 6633 解决: 1263 题目描述 给定 n, m ,问是否存在两个不同的数 x, y 使得 1 ≤ x < y ≤ m 且 n mod x n mod y 。 输入格式 输入包含多…...
【LeetCode 题解】算法:36.有效的数独
一、问题剖析 在算法领域中,数独问题是一个经典且有趣的逻辑验证题目。本题的核心任务是判断一个给定的 9x9 数独是否有效。判断的依据是数独的基本规则:数字 1-9 在每一行、每一列以及每一个 3x3 的宫内都只能出现一次。同时,题目中明确指出…...
C++学习之MYSQL数据库
目录 1.mysql数据库介绍 2.mysql数据库安装 3.mysql数据库启动和登录 4.mysql数据库CURD 5.mysql数据库表CURD 6.mysql数据库数据CURD 7.mysql基础综合练习 8.mysql数据库总日期和时间函数 9.mysql中函数 10.PLSQL工具使用介绍 11.ORACLE实例别名和ORACLE客户端 12.…...