当前位置: 首页 > news >正文

可以做动漫的网站/百度总部

可以做动漫的网站,百度总部,app快速开发框架,找个做网站的🔥 本文由 程序喵正在路上 原创,CSDN首发! 💖 系列专栏:Springcloud微服务 🌠 首发时间:2024年6月4日 🦋 欢迎关注🖱点赞👍收藏🌟留言&#x1f43…

🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:Springcloud微服务
🌠 首发时间:2024年6月4日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾

目录

  • 扩展功能
    • 代码生成
    • 静态工具
    • 逻辑删除
    • 枚举处理器
    • JSON处理器
  • 插件功能
    • 分页插件
    • 通用分页实体

扩展功能

代码生成

在使用 MybatisPlus 以后,基础的 Mapper、Service、PO 代码相对固定,重复编写也比较麻烦。因此 MybatisPlus 官方提供了代码生成器根据数据库表结构生成 PO、Mapper、Service 等相关代码。只不过代码生成器同样要编码使用,也很麻烦。

所以这里推荐使用另外一款 MybatisPlus 的插件,它可以基于图形化界面完成 MybatisPlus 的代码生成,非常简单。

安装插件

在 Idea 的 plugins 市场中搜索并安装 MyBatisPlus 插件:

在这里插入图片描述
然后重启你的 Idea 即可使用。

使用

刚好数据库中还有一张 address 表尚未生成对应的实体和 mapper 等基础代码,我们可以利用插件生成一下。

首先需要配置数据库地址,在 Idea 顶部菜单中,找到 other,选择 Config Database,然后填写一些信息:
在这里插入图片描述

然后再次点击 Idea 顶部菜单中的 other,然后选择 Code Generator,填写表单信息:

在这里插入图片描述
示例:

在这里插入图片描述

在这里插入图片描述

静态工具

有的时候 Service 之间也会相互调用,为了避免出现循环依赖问题,MybatisPlus 提供一个静态工具类:Db,其中的一些静态方法与 IService 中方法签名基本一致,也可以帮助我们实现 CRUD 功能:

在这里插入图片描述
下面,我们通过一些案例来学习使用静态工具。

需求:

1、改造根据 id 查询用户的接口,查询用户的同时,查询出用户对应的所有地址

由于现在需要额外返回收货地址,所以我们需要定义一个收货地址的 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 查询用户的业务接口,新建一个方法:

/*** 根据id查询用户** @param userId* @return*/
@GetMapping("/{id}")
@ApiOperation("根据id查询用户")
public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Long userId) {return userService.queryUserAndAddressById(userId);
}

IUserService 接口中声明该方法:

/*** 根据id查询用户及其收货地址** @param userId* @return*/
UserVO queryUserAndAddressById(Long userId);

UserServiceImpl 中实现方法:

/*** 根据id查询用户及其收货地址** @param userId* @return*/
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.封装数据UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);// 先判断收货地址列表是否为空if (CollUtil.isNotEmpty(addresses)) {userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));}// 4.返回数据return userVO;
}

测试:

在这里插入图片描述

2、改造根据 id 批量查询用户的接口,查询用户的同时,查询出用户对应的所有地址

UserController:

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

UserServiceImpl:

/*** 根据id集合查询用户及其收货地址** @param ids* @return*/
public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {// 1.查询用户List<User> users = listByIds(ids);if (CollUtil.isEmpty(users)) {return Collections.emptyList(); // 返回空列表}// 2.查询收货地址List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, ids).list(); //根据用户id查询收货地址List<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);    //转化地址VO//将用户收货地址分组处理,相同用户的放入一个集合中Map<Long, List<AddressVO>> addressMap = new HashMap<>(0);if (CollUtil.isNotEmpty(addressVOList)) {addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));}// 3.封装数据List<UserVO> list = new ArrayList<>(users.size());for (User user : users) {UserVO vo = BeanUtil.copyProperties(user, UserVO.class);    // 拷贝用户信息vo.setAddresses(addressMap.get(user.getId()));  // 设置用户收货地址list.add(vo);}return list;
}

测试:

在这里插入图片描述

逻辑删除

逻辑删除就是基于代码逻辑模拟删除效果,但并不会真正删除数据库中的数据。思路如下:

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为 1
  • 查询时只查询标记为 0 的数据

一旦采用了逻辑删除,所有的查询和删除逻辑都要跟着变化,非常麻烦。

为了解决这个问题,MybatisPlus 提供了逻辑删除功能,无需改变方法调用的方式,而是在底层帮我们自动修改 CRUD 的语句。我们要做的就是在 application.yaml 文件中配置逻辑删除的字段名称和值即可:

在 Address 实体类中已经存在一个字段 deleted 用于逻辑删除,所以我们不用再定义:

在这里插入图片描述

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, 可以不配置)

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

写一个测试类测试一下:

package com.itheima.mp.service;import com.itheima.mp.domain.po.Address;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest
class IAddressServiceTest {@Autowiredprivate IAddressService addressService;@Testvoid testDeleteByLogic() {// 删除方法与以前没有区别addressService.removeById(59L);}@Testvoid testQuery() {List<Address> list = addressService.list();list.forEach(System.out::println);}
}

先执行第一个测试方法,进行删除,结果如下:

在这里插入图片描述

再执行第二个方法查询一下,结果如下:

在这里插入图片描述

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

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

  • 会导致数据库表垃圾数据越来越多,影响查询效率
  • SQL 中全都需要对逻辑删除字段做判断,影响查询效率

因此,还是不太推荐采用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其它表的办法。

枚举处理器

User 类中有一个用户状态字段:

在这里插入图片描述

像这种字段我们一般会定义一个枚举,做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是 int 类型,对应的PO也是 Integer。因此业务操作时必须手动把枚举与 Integer 转换,非常麻烦。

因此,MybatisPlus 提供了一个处理枚举的类型转换器,可以帮我们把枚举类型与数据库类型自动转换。

定义枚举

我们定义一个用户状态的枚举:

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 类中和 UserVO 中的 status 字段改为 UserStatus 类型。

将 UserServiceImpl 代码中的 2 替换为 UserStatus.FREEZE,显得更专业一点。

要让 MybatisPlus 处理枚举与数据库类型自动转换,我们必须告诉 MybatisPlus,枚举中的哪个字段的值作为数据库值。

MybatisPlus 中提供了 @EnumValue 注解来标记枚举属性:

在这里插入图片描述

配置枚举处理器

在 application.yaml 文件中添加配置:

mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

然后我们测试一下查询:

在这里插入图片描述

查询成功,不过查询出的 User 类的 status 字段是枚举类型,可能不是很好理解。

我们在 UserStatus 枚举中通过 @JsonValue 注解标记 JSON 序列化时要展示的字段,添加在 value 或者 desc 上都可以:

比如,我们添加在 desc 上,就会显示 “正常” 或者 “冻结”:

在这里插入图片描述

在这里插入图片描述

JSON处理器

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

在这里插入图片描述

而目前我们的 User 实体类中却是 String 类型的:

在这里插入图片描述

这样一来,我们要读取 info 中的属性时就非常不方便。如果要方便获取,info 的类型最好是一个 Map 或者实体类。

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

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

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

定义实体

首先,我们在 po 下定义一个单独实体类 UserInfo 来与 info 字段的属性匹配:

package com.itheima.mp.domain.po;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor(staticName = "of")
public class UserInfo {private Integer age;private String intro;private String gender;
}

使用类型处理器

接下来,将 User 类的 info 字段修改为 UserInfo 类型,并声明类型处理器,同时开启结果自动映射;UserVO 中的 info 字段也需要修改为 UserInfo 类型:

package com.itheima.mp.domain.po;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 com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.itheima.mp.enums.UserStatus;
import lombok.Data;import java.time.LocalDateTime;@Data
@TableName(value = "user", autoResultMap = true)    //开启结果自动映射
public class User {@TableId(type = IdType.AUTO)    //不指定的话,默认为随机生成id,也就是第三种方式private Long id;                //用户idprivate String username;        //用户名private String password;        //密码private String phone;           //注册手机号@TableField(typeHandler = JacksonTypeHandler.class)private UserInfo info;            //详细信息private UserStatus status;      //使用状态(1正常 2冻结)private Integer balance;        //账户余额private LocalDateTime createTime;//创建时间private LocalDateTime updateTime;//更新时间
}

将测试方法中关于设置详细信息的代码修改一下:

在这里插入图片描述

重启服务,测试一下查询接口,可以看到信息成功返回:

在这里插入图片描述

插件功能

MybatisPlus 提供了很多的插件功能,进一步拓展其功能。目前已有的插件有:

  • PaginationInnerInterceptor:自动分页
  • TenantLineInnerInterceptor:多租户
  • DynamicTableNameInnerInterceptor:动态表名
  • OptimisticLockerInnerInterceptor:乐观锁
  • IllegalSQLInnerInterceptor:sql 性能规范
  • BlockAttackInnerInterceptor:防止全表更新与删除

最常用的是自动分页插件。

分页插件

在未引入分页插件的情况下,MybatisPlus 是不支持分页功能的,IService 和 BaseMapper 中的分页方法都无法正常起效。所以,我们必须配置分页插件。

在项目中新建一个配置类,项目结构如下:

在这里插入图片描述

package com.itheima.mp.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MybatisConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {// 1.初始化核心插件MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 2.创建分页插件PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();paginationInnerInterceptor.setMaxLimit(1000L);  //设置最大分页限制// 3.添加分页插件interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;}
}

在 IUserServiceTest 中写一个分页查询的测试方法:

@Test
void testPageQuery() {// 1.准备分页条件int pageNum = 1, pageSize = 2;  //页码、每页大小Page<User> page = Page.of(pageNum, pageSize);// 2.排序条件page.addOrder(new OrderItem("balance", true));  // 先按余额升序排序page.addOrder(new OrderItem("id", true));       // 再按id升序排序// 3.分页查询Page<User> p = userService.page(page);// 4.解析数据long total = p.getTotal();  // 总条数System.out.println("total = " + total);long pages = p.getPages();// 总页数System.out.println("pages = " + pages);List<User> users = p.getRecords();  // 当前页码的数据记录users.forEach(System.out::println);
}

结果:

在这里插入图片描述

通用分页实体

需求:遵循下面的接口规范,编写一个 UserController 接口,实现 User 的分页查询。

在这里插入图片描述
定义实体

这里需要定义3个实体:

  • UserQuery:分页查询条件的实体,包含分页、排序参数、过滤条件
  • PageDTO:分页结果实体,包含总条数、总页数、当前页数据
  • UserVO:用户页面视图实体(已存在)

虽然 UserQuery 之前已经定义过了,并且其中已经包含了过滤条件,其中缺少的仅仅是分页条件,但是分页条件不仅仅是用户分页查询需要,以后其它业务也都有分页查询的需求。因此建议将分页查询条件单独定义为一个 PageQuery 实体:

PageQuery 是前端提交的查询参数,一般包含四个属性:

  • pageNo:页码
  • pageSize:每页数据条数
  • sortBy:排序字段
  • isAsc:是否升序
package com.itheima.mp.domain.query;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {@ApiModelProperty("页码")private Long pageNo;@ApiModelProperty("每页数据条数")private Long pageSize;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc;
}

然后,让我们的 UserQuery 继承这个实体:

package com.itheima.mp.domain.query;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;@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;
}

最后,则是分页实体 PageDTO,由于在其它微服务项目中可能也会使用到这个分页实体,我们将其定为为 DTO:

package com.itheima.mp.domain.dto;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.List;@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {@ApiModelProperty("总条数")private Long total;@ApiModelProperty("总页数")private Long pages;@ApiModelProperty("集合")private List<T> list;
}

开发接口

在 UserController 中定义分页查询用户的接口:

/*** 根据条件分页查询用户** @param query* @return*/
@GetMapping("/page")
@ApiOperation("根据条件分页查询用户接口")
public PageDTO<UserVO> queryUsersPage(UserQuery query) {return userService.queryUsersPage(query);
}

在 IUserService 中创建 queryUsersPage 方法:

/*** 根据条件分页查询用户** @param query* @return*/
PageDTO<UserVO> queryUsersPage(UserQuery query);

在 UserServiceImpl 中实现该方法:

/*** 根据条件分页查询用户** @param query* @return*/
public PageDTO<UserVO> queryUsersPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();// 构建分页条件Page<User> page = Page.of(query.getPageNo(), query.getPageSize()); 3// 排序条件if (StrUtil.isNotBlank(query.getSortBy())) {// 不为空page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));} else {// 为空,默认按照更新时间排序page.addOrder(new OrderItem("update_time", query.getIsAsc()));}// 分页查询Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);//封装VO结果PageDTO<UserVO> dto = new PageDTO<>();dto.setTotal(p.getTotal());dto.setPages(p.getPages());List<User> records = p.getRecords();if (CollUtil.isEmpty(records)) {// 为空,设置为空列表dto.setList(Collections.emptyList());} else {// 不为空dto.setList(BeanUtil.copyToList(records, UserVO.class));}return dto;
}

测试一下:

在这里插入图片描述

改造PageQuery实体

在上面的代码中,从 PageQuery 到 MybatisPlus 的 Page 之间转换的过程还是比较麻烦的。

我们完全可以在 PageQuery 这个实体中定义一个工具方法,来简化开发。

package com.itheima.mp.domain.query;import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {@ApiModelProperty("页码")private Long pageNo = 1L;@ApiModelProperty("每页数据条数")private Long pageSize = 2L;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc = true;// 多个参数public <T> Page<T> toMpPage(OrderItem... orders) {// 分页条件Page<T> page = Page.of(pageNo, pageSize);// 排序条件if (StrUtil.isNotBlank(sortBy)) {// 不为空page.addOrder(new OrderItem(sortBy, isAsc));} else if (orders != null) {// 为空page.addOrder(orders);}return page;}// 只有一个参数public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc) {return toMpPage(new OrderItem(defaultSortBy, isAsc));}// 没有参数,希望按照创建时间排序public <T> Page<T> toMpPageDefaultSortByCreateTimeDesc() {return toMpPage("create_time", false);}// 没有参数,希望按照更新时间排序public <T> Page<T> toMpPageDefaultSortByUpdateTimeDesc() {return toMpPage("update_time", false);}
}

这样我们在开发也时就可以省去对从 PageQuery 到 Page 的的转换:

// 构建分页条件
Page<User> page = query.toMpPageDefaultSortByUpdateTimeDesc();

改造PageDTO实体

同理,在查询出分页结果后,数据的非空校验,数据的 vo 转换都是模板代码,编写起来很麻烦。

我们完全可以将其封装到 PageDTO 的工具方法中,简化整个过程:

package com.itheima.mp.domain.dto;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;@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, Class<VO> clazz) {PageDTO<VO> dto = new PageDTO<>();dto.setTotal(p.getTotal());     // 总条数dto.setPages(p.getPages());     // 总页数// 当前页数据List<PO> records = p.getRecords();if (CollUtil.isEmpty(records)) {// 为空,设置为空里欸博爱dto.setList(Collections.emptyList());} else {// 不为空dto.setList(BeanUtil.copyToList(records, clazz));}return dto;}// 需要传PO如何转换为VO的方法public static <PO, VO> PageDTO<VO> of(Page<PO> p, Function<PO, VO> convertor) {PageDTO<VO> dto = new PageDTO<>();dto.setTotal(p.getTotal());     // 总条数dto.setPages(p.getPages());     // 总页数// 当前页数据List<PO> records = p.getRecords();if (CollUtil.isEmpty(records)) {// 为空,设置为空里欸博爱dto.setList(Collections.emptyList());} else {// 不为空dto.setList(records.stream().map(convertor).collect(Collectors.toList()));}return dto;}
}

最终,业务层的代码可以简化为:

public PageDTO<UserVO> queryUsersPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();// 构建分页条件Page<User> page = query.toMpPageDefaultSortByUpdateTimeDesc();// 分页查询Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);return PageDTO.of(p, UserVO.class);
}

如果是希望自定义 PO 到 VO 的转换过程,可以这样做:

return PageDTO.of(p, user -> {// 1.拷贝基础属性UserVO vo = BeanUtil.copyProperties(user, UserVO.class);// 2.处理特殊逻辑:比如用户名脱敏String username = vo.getUsername();vo.setUsername(username.substring(0, username.length() - 2) + "**");return vo;
});

测试一下:

在这里插入图片描述

在改进的过程中,我们都是在实体类中添加了对应的方法来简化我们的开发,这也意味着这些方法和实体类耦合了。因为我们使用的是 MP,所以可以这样写,如果使用的不是 MP,我们可以考虑定义一些工具类来实现这些类型之间的转换,以此让方法与实体类解耦合。

相关文章:

【Springcloud微服务】MybatisPlus下篇

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;Springcloud微服务 &#x1f320; 首发时间&#xff1a;2024年6月4日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43…...

i18n-demo

一、demo 1、资源文件准备 如我需要对menu、logMsg内容做国际化。 resources下放各个语言文件&#xff0c;直接放resources下都行。我是新建了一个myi18n文件夹&#xff0c; &#xff08;1&#xff09;然后在myi18n上点击New--Resource Bundle &#xff08;2&#xff09;在…...

[Leetcode] 0-1背包和完全背包

46. 携带研究材料 纯01背包&#xff08;非应用&#xff09;&#xff1a;只能选择一次物品 dp[j]&#xff1a;容量为j的背包所能装的最大容量 容量需要倒序 416. 分割等和子集 能否装满 dp[j]&#xff1a;容量为j的背包所能装的最大容量 1049. 最后一块石头的重量 II 尽可…...

自定义类型:联合体和枚举

1. 联合体类型的声明 2. 联合体的特点 3. 联合体大小的计算 4. 枚举类型的声明 5. 枚举类型的优点 6. 枚举类型的使用 欢迎关注 熬夜学编程 创作不易&#xff0c;请多多支持 感谢大家的阅读、点赞、收藏和关注 如有问题&#xff0c;欢迎指正 1. 联合体 1.1 联合体类型的声…...

【Cityengine】Cityengine生产带纹理的建筑模型导入UE4/UE5(下)

【Cityengine】Cityengine生产带纹理的建筑模型导入UE4/UE5&#xff08;下&#xff09; 一、导出数据&#xff08;2022中文版案例&#xff09;二、安装datasmith插件三、导入数据四、检查导入材质是否正常五、编辑替换材质六、安装模型编辑插件七、编辑替换建筑规则 一、导出数…...

详解51种企业应用架构模式

导读&#xff1a;企业应用包括哪些&#xff1f;它们又分别有哪些架构模式&#xff1f;世界著名软件开发大师Martin Fowler给你答案 01、什么是企业应用 我的职业生涯专注于企业应用&#xff0c;因此&#xff0c;这里所谈及的模式也都是关于企业应用的。&#xff08;企业应用还…...

【十年java搬砖路】Jumpserver docker版安装及配置Ldap登陆认证

Jumpserver docker 安装启动教程 拉取镜像 docker pull JumpServer启动进行前确保有Redis 和Mysql 创建jumperServer数据库 在MYSQL上执行 创建数据库 登陆MYSQL mysql -u root -p 创建Jumperserveri库 create database jumpserver default charset utf8mb4;可以为jumperSe…...

C\C++内存管理(未完结)

文章目录 一.C\C内存分布二.C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free三.C内存管理方式3.1.new/delete操作内置类型3.2.new和delete操作自定义类型 四.operator new与operator delete函数&#xff08;重要点进行讲解&#xff09;4.1. operator new与oper…...

一个小时搞定JAVA面向对象(5)——抽象与接口

文章目录 抽象抽象的注意事项static\final\private是否可以修饰抽象方法继承和抽象知识点回顾 接口接口实现总结抽象方法默认方法静态方法成员变量接口的特点接口和抽象类的区别 抽象 关键字: abstract 抽象方法: 修饰符 abstract 返回值类型 方法名(参数); 抽象类: public a…...

图像关键特征描述方法-小目标

图像关键特征描述方法主要包括以下几种: SIFT(尺度不变特征变换): SIFT是一种广泛使用的特征描述方法,它通过尺度空间和梯度方向直方图来描述图像中的关键点。SIFT特征描述具有尺度不变性和旋转不变性,对于光照和视角变化也具有一定的鲁棒性。 SURF(加速稳健特征): SURF…...

【qt15】windeployqt 安装依赖

debug模式vs可以使用qt插件新建qt文件 D:\Qt15\5.15.2\msvc2019\bin\windeployqt.exe Warning: Cannot find Visual Studio installation directory, VCINSTALLDIR is not set.D:\Qt15\5.15.2\msvc2019\bin\windeployqt.exe .\filecopier.exeWindows PowerShell Copyright (C) …...

DETR论文重点

DETR就是 DEtection TRansformer 的缩写。 论文原名&#xff1a;End-to-End Object Detection with Transoformers。 重点有两个&#xff1a;端到端、Transformer结构 论文概述 注意&#xff1a;斜体的文字为论文原文&#xff0c;其他部分内容则是为增进理解而做的解释。 …...

slf4j等多个jar包冲突绑定的排查方法使用IDEA的maven help解决

1.安装 2.使用maven help解决&#xff0c;找到对应包存在的冲突 使用exclude直接解决即可...

MySQL主从的延迟怎么解决呢?

以下是一些减少或解决MySQL主从延迟的策略&#xff1a; 优化查询和索引&#xff1a; 确保所有的查询都经过优化&#xff0c;以减少主服务器上的负载。使用合适的索引来加速查询速度&#xff0c;减少锁的时间。 分散复制负载&#xff1a; 使用多个从服务器分散读取负载。使用并…...

【一百】【算法分析与设计】N皇后问题常规解法+位运算解法

N皇后问题 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 给出一个nnn\times nnn的国际象棋棋盘&#xff0c;你需要在棋盘中摆放nnn个皇后&#xff0c;使得任意两个皇后之间不能互相攻击。具体来说&#xff0c;不能存在两个皇后位于同…...

GPT-4:人工智能领域的新里程碑

近期&#xff0c;OpenAI推出了备受瞩目的GPT-4。作为GPT系列的最新成员&#xff0c;GPT-4在自然语言处理&#xff08;NLP&#xff09;领域再次刷新了记录&#xff0c;引发了广泛的关注和讨论。在试用GPT-4之后&#xff0c;我深感其在技术能力、应用场景等方面都取得了显著的进步…...

mysql inset bug

在 SQL 中&#xff0c;日期值需要用单引号包围&#xff0c;这是因为 SQL 将日期值视为字符串格式。数据库引擎在处理这些值时会将它们解析为适当的日期类型。如果不使用单引号&#xff0c;数据库引擎会将它们视为数字或列名&#xff0c;从而导致语法错误。 日期格式 MySQL 支…...

oracle查看序列

在Oracle数据库中&#xff0c;查看序列的方式主要有以下几种&#xff1a; 查看当前用户下的所有序列名称&#xff1a; sql复制代码 SELECT sequence_name FROM user_sequences; 查看所有用户的序列&#xff1a; sql复制代码 SELECT sequence_name FROM all_sequences; 查看…...

flask-slqalchemy使用详解

目录 1、flask-sqlalchemy 1.1、flask_sqlalchemy 与sqlalchemy 的关系 1.1.1、 基本定义与用途 1.2、flask_sqlalchemy 的使用 1.2.1、安装相关的库 1.2.2、项目准备 1.2.3、创建ORM模型 1.2.3.1、使用db.create_all()创建表的示例 1.2.3.2、创建多表关联ORM模型 1.…...

Scala学习笔记8: 包

目录 第八章 包1- 包2- 包的作用域3- 串联式包语句4- 包对象5- 引入end 第八章 包 在Scala中, 包(Package) 用于组织和管理代码, 类似与 Java 中的包 ; 包可以包含类、对象、特质等Scala代码, 并通过层次结构来组织代码 ; 可以使用 package 关键字来定义包, 并使用 . 来表示…...

分享一份糟糕透顶的简历,看看跟你写的一样不

最近看了一个人的简历&#xff0c;怎么说呢&#xff0c;前几年这么写没问题&#xff0c;投出去就有回复&#xff0c;但从现在开始&#xff0c;这么写肯定不行了。下面我给大家分享一下内容&#xff1a; 目录 &#x1f926;‍♀️这是简历文档截图 &#x1f937;‍♀️这是基本…...

VMware 三种网络模式

目录 一、网卡、路由器、交换机 二、虚拟网络编辑器 三、网络模式 1.桥接模式 通信方式 特点 配置 连通情况 使用场景 2.NAT模式 通信方式 特点 配置 连通情况 使用场景 3.仅主机 通信方式 特点 配置 连通情况 使用场景 一、网卡、路由器、交换机 网卡(Ne…...

红绿二分查找

《英雄算法零基础》之 二分查找 https://articles.zsxq.com/id_ib4xgs0cogic.html 在写模版之前我们先搞清楚二分查找是怎样运行的&#xff0c;我们把一个数组分成红绿两种颜色&#xff0c;可以理解为绿色就是符合情况的&#xff0c;红色就是不符合情况的&#xff08;类似红绿灯…...

C51单片机 串口打印printf重定向

uart.c文件 #include "uart.h"void UartInit(void) //4800bps11.0592MHz {PCON | 0x80; //使能波特率倍速位SMODSCON 0x50; //8位数据,可变波特率。使能接收TMOD & 0x0F; //清除定时器1模式位TMOD | 0x20; //设定定时器1为8位自动重装方式TL1 0xF4; //设…...

PieCloudDB Database Flink Connector:让数据流动起来

面对客户环境中长期运行的各种类型的传统数据库&#xff0c;如何优雅地设计数据迁移的方案&#xff0c;既能灵活地应对各种数据导入场景和多源异构数据库&#xff0c;又能满足客户对数据导入结果的准确性、一致性、实时性的要求&#xff0c;让客户平滑地迁移到 PieCloudDB 数据…...

主机CPU访问PCIe设备内存空间和PCIe设备访问主机内存空间

在x86体系架构中&#xff0c;主机CPU访问PCIe设备内存空间和PCIe设备访问主机内存空间的过程涉及多个层次的地址映射和转换。以下是详细的解释&#xff1a; 主机CPU访问PCIe设备内存空间 1. CPU生成虚拟地址&#xff08;Virtual Address, VA&#xff09;: 在x86架构中&#…...

在家AIAA(美国航空航天学会)文献如何查找下载

今天有位同学的求助文献来自AIAA&#xff08;美国航空航天学会&#xff09;&#xff0c;下面就讲一下不用求助他人自己就可搞定文献下载的途径并实例操作演示。 首先我们先对AIAA&#xff08;美国航空航天学会&#xff09;数据库做个简单的了解&#xff1a; 美国航空航天学会…...

dnf手游版游玩感悟

dnf手游于5月21号正式上线&#xff0c;作为一个dnf端游老玩家&#xff0c;并且偶尔上线ppk&#xff0c;自然下载了手游版&#xff0c;且玩了几天。 不得不说dnf手游的优化做到了极好的程度。 就玩法系统这块&#xff0c;因为dnf属于城镇地下城模式&#xff0c;相比…...

安卓如何书写注册和登录界面

一、如何跳转一个活动 左边的是本活动名称&#xff0c; 右边的是跳转界面活动名称 Intent intent new Intent(LoginActivity.this, RegisterActivity.class); startActivity(intent); finish(); 二、如果在不同的界面传递参数 //发送消息 SharedPreferences sharedPreferen…...

黄仁勋的AI时代:英伟达GPU革命的狂欢与挑战

在最近的COMPUTEX 2024大会上&#xff0c;英伟达创始人黄仁勋发布了最新的Blackwell GPU。这次发布不仅标志着英伟达在AI领域的又一次飞跃&#xff0c;也展示了其对未来技术发展的战略规划。本文将详细解析英伟达最新技术的亮点&#xff0c;探讨其在AI时代的市场地位和未来挑战…...