代码生成
逻辑删除
枚举处理器
json处理器
配置加密
分页插件
https://blog.csdn.net/weixin_41957626/article/details/132651552
下载下面的插件
红色的是刚刚生成的。
我觉得不如官方的那个好用,唯一的好处就是勾选的选项能够看的懂得。
不是真的删除是进行uupdate的操作,把对应的标志位设置为对应的标志就可以的
mp中可以采用全局的配置设置对应的逻辑删除的操作达到和原先逻辑删除一样的方式。
下面是全局的配置。
global-config:
db-config:
logic-delete-field: flag #全局删除的实体的字段名
logic-delete-value: 1 #逻辑删除值
logic-not-delete-value: 0 #逻辑未删除的值
说明所有的 表的都是基于下面的格式的。
可以在指定的表的字段上进行设置逻辑删除的字段需要进行单独的设置的。
在数据库中添加逻辑删除的字段。
测试对address的逻辑删除
@Test
void tes61(){
boolean flag= addressService.removeById(59L);
System.out.println("删除的结果="+flag);
}
删除的结果
JDBC Connection [HikariProxyConnection@118887511 wrapping com.mysql.cj.jdbc.ConnectionImpl@38ee7a9d] will not be managed by Spring
==> Preparing: UPDATE address SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 59(Long)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@39c96e48]
删除的结果=true
@Test
void tes62(){
Address address= addressService.getById(59L);
System.out.println("address="+address);
}
查询的结果
JDBC Connection [HikariProxyConnection@571251299 wrapping com.mysql.cj.jdbc.ConnectionImpl@55b5cd2b] will not be managed by Spring
==> Preparing: SELECT id,user_id,province,city,town,mobile,street,contact,is_default,notes,deleted FROM address WHERE id=? AND deleted=0
==> Parameters: 59(Long)
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@ebe067d]
address=null
此时我们进行逻辑删除的内容找不到了
数据库中的逻辑删除字段类型的设置
可以采用位的方式,也可以采用int的类型。
采用int的类型
此时在idea中显示的就是0和1,在代码的设计上需要注意一个问题false需要和0进行对应,1需要和true进行对应。
采用位的类型也是相似的道理但是直接显示的时候是不同的。
采用位的时候需要进行转义。
@Test
void tes63(){
Address address= addressService.getById(60L);
System.out.println("address="+address);
}
==> Preparing: SELECT id,user_id,province,city,town,mobile,street,contact,is_default,notes,deleted FROM address WHERE id=? AND deleted=0
==> Parameters: 60(Long)
<== Columns: id, user_id, province, city, town, mobile, street, contact, is_default, notes, deleted
<== Row: 60, 1, 北京, 北京, 朝阳区, 13700221122, 修正大厦, Jack, 0, null, 0
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@205df5dc]
address=Address(id=60, userId=1, province=北京, city=北京, town=朝阳区, mobile=13700221122, street=修正大厦, contact=Jack, isDefault=false, notes=null, deleted=false)
像是状态的字段可以采用对应的状态转换器进行转换。
枚举类型是比常量更加标准的数据的类型。
/**
* 使用状态(1正常 2冻结)
*/
private Integer status;
从枚举类中进行插入的时候需要时候不推荐间接调用的方式。有没有一种方式可以直接枚举类型的转换呢。
mp原先就帮我们定义好了对应的枚举类型的处理器。我们直接进行调用就可以了。
下面是原先类的属性和枚举类的对应的关系。
//用户状态信息
@AllArgsConstructor
@Getter
public enum UserStatus {
NORMAL(1,"正常"),
FREEZE(2,"冻结");
@EnumValue
private final int value;
private final String desc;
}
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
// private Integer status;
private UserStatus status;
@Test
void tes64(){
User user=new User();
user.setUsername("赵天");
user.setPassword("123456");
user.setPhone("102");
JSONObject jsonObject=new JSONObject();
//hutool中的
jsonObject.set("age",20);
jsonObject.set("intro","伏地魔");
jsonObject.set("gender","female");
user.setInfo(jsonObject.toString());
user.setStatus(UserStatus.NORMAL);
user.setBalance(2000);
user.setCreateTime(DateTime.now());
user.setUpdateTime(DateTime.now());
boolean flag= userService.save(user);
System.out.println("是否插入成功="+flag);
}
JDBC Connection [HikariProxyConnection@1844349670 wrapping com.mysql.cj.jdbc.ConnectionImpl@5af64ce0] will not be managed by Spring
==> Preparing: INSERT INTO user ( username, password, phone, info, status, balance, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )
==> Parameters: 赵天(String), 123456(String), 102(String), {"age":20,"intro":"伏地魔","gender":"female"}(String), 1(Integer), 2000(Integer), 2023-09-03 16:55:18.777(Timestamp), 2023-09-03 16:55:18.778(Timestamp)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@345d053b]
是否插入成功=true
@Test
void tes65(){
User user=userService.lambdaQuery()
.eq(User::getUsername,"赵天").one();
System.out.println(user.toString());
}
查询出来的结果
User(id=1674613593516396924, username=赵天, password=123456, phone=102, info={"age": 20, "intro": "伏地魔", "gender": "female"}, status=NORMAL, balance=2000, createTime=Sun Sep 03 16:55:19 CST 2023, updateTime=Sun Sep 03 16:55:19 CST 2023)
如何将json字符串转换成对应的类的对象
这个不是全局的。mvc底层最长用的就是jackson的不是json的类型处理器。
private Object info;
@TableField(typeHandler = JacksonTypeHandler.class)
private UserInfo info;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class UserInfo implements Serializable {
private Integer age;
private String intro;
private String gender;
}
@Test
void tes65(){
User user=userService.lambdaQuery()
.eq(User::getUsername,"赵天").one();
System.out.println(user.toString());
}
JDBC Connection [HikariProxyConnection@1451516720 wrapping com.mysql.cj.jdbc.ConnectionImpl@49f3ff41] will not be managed by Spring
==> Preparing: SELECT id,username,password,phone,info,status,balance,create_time,update_time FROM user WHERE (username = ?)
==> Parameters: 赵天(String)
<== Columns: id, username, password, phone, info, status, balance, create_time, update_time
<== Row: 1674613593516396924, 赵天, 123456, 102, <>, 1, 2000, 2023-09-03 16:55:19, 2023-09-03 16:55:19
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6d099323]
User(id=1674613593516396924, username=赵天, password=123456, phone=102, info=null, status=NORMAL, balance=2000, createTime=Sun Sep 03 16:55:19 CST 2023, updateTime=Sun Sep 03 16:55:19 CST 2023)
出现上面的原因是我们没有设置resultMap的值
最简单的解决的方式:设置自动映射。
@TableName(value ="user",autoResultMap = true)
此时查询的值就出现了。
JDBC Connection [HikariProxyConnection@998015174 wrapping com.mysql.cj.jdbc.ConnectionImpl@3b2e5c0d] will not be managed by Spring
==> Preparing: SELECT id,username,password,phone,info,status,balance,create_time,update_time FROM user WHERE (username = ?)
==> Parameters: 赵天(String)
<== Columns: id, username, password, phone, info, status, balance, create_time, update_time
<== Row: 1674613593516396924, 赵天, 123456, 102, <>, 1, 2000, 2023-09-03 16:55:19, 2023-09-03 16:55:19
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7c1447b5]
User(id=1674613593516396924, username=赵天, password=123456, phone=102, info=UserInfo(age=20, intro=伏地魔, gender=female), status=NORMAL, balance=2000, createTime=Sun Sep 03 16:55:19 CST 2023, updateTime=Sun Sep 03 16:55:19 CST 2023)
或者是采用自己指定的方式
@TableName(value ="user",resultMap = "BaseResultMap")
mp默认是提供一个aes算法的加密的工具,对配置中的敏感信息做加密处理
生成加密的账号和密码
@Test
public void test1(){
//生成16位随机aes密钥
String randomKey= AES.generateRandomKey();
System.out.println("randomKey="+randomKey);
//利用密钥对用户名和密码进行加密
String username=AES.encrypt("root",randomKey);
System.out.println("username="+username);
//利用密钥对密码加密
String password=AES.encrypt("root",randomKey);
System.out.println("password="+password);
}
下面是生成的加密的账号和密码以及用于加密和解密的密钥:
randomKey=19cb291382b38782
username=ebMDrqWwkpNR9jkM+2x5Iw==
password=ebMDrqWwkpNR9jkM+2x5Iw==
将加密之后的配置到配置文件中
spring:
datasource:
url: jdbc:mysql://localhost:3306/mp?useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
username: mpw:ebMDrqWwkpNR9jkM+2x5Iw== #加密
password: mpw:ebMDrqWwkpNR9jkM+2x5Iw== #加密
driver-class-name: com.mysql.cj.jdbc.Driver
启动的时候加上对应的启动的参数
@SpringBootTest(args = "--mpw.key=19cb291382b38782")
@Test
void tes65(){
User user=userService.lambdaQuery()
.eq(User::getUsername,"赵天").one();
System.out.println(user.toString());
}
查询结果:
JDBC Connection [HikariProxyConnection@180949634 wrapping com.mysql.cj.jdbc.ConnectionImpl@7f79edee] will not be managed by Spring
==> Preparing: SELECT * FROM user WHERE (username = ?)
==> Parameters: 赵天(String)
<== Columns: id, username, password, phone, info, status, balance, create_time, update_time
<== Row: 1674613593516396924, 赵天, 123456, 102, <>, 1, 2000, 2023-09-03 16:55:19, 2023-09-03 16:55:19
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@568750b7]
User(id=1674613593516396924, username=赵天, password=123456, phone=102, info=UserInfo(age=20, intro=伏地魔, gender=female), status=NORMAL, balance=2000, createTime=Sun Sep 03 16:55:19 CST 2023, updateTime=Sun Sep 03 16:55:19 CST 2023)
说明解密的密码成功了。
本质是拦截器功能
@Configuration
//@MapperScan("com.lxz.demo.mapper")
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
测试简单的分页
@Test
void tes65(){
//分页参数
Integer pageNum=1;
Integer pageSize=10;
//分页对象
Page page=new Page(pageNum, pageSize);
//排序
page.addOrder(new OrderItem("username",false));
//其他参数
page=userService.page(page);
Long count=page.getTotal();
List result=page.getRecords();
System.out.println("count="+count);
result.forEach(System.out::println);
}
//排序 这个是升序
page.addOrder(new OrderItem("username",true));
有查询条件的
page=userService.page(page,null);
接口内容:
package com.lxz.demo.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
//返回结果
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageVo implements Serializable {
private Long total;
private Long pages;
/*
* 采用泛型是最好的
* */
private List list;
}
package com.lxz.demo.domain.vo;
import com.lxz.demo.domain.UserInfo;
import com.lxz.demo.enums.UserStatus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
//返回结果
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserVo implements Serializable {
private Long id;
private String username;
private UserInfo info;
private UserStatus status;
private Long balance;
}
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/page")
public PageVo queryUserByPage(@RequestBody PageQuery query){
return userService.queryUserByPage(query);
}
}
或者
区别在于注入的方式是不同的
@RestController
@RequestMapping("/users2")
@RequiredArgsConstructor
public class UserController2 {
private final UserService userService;
@PostMapping("/page")
public PageVo queryUserByPage(@RequestBody PageQuery query){
return userService.queryUserByPage(query);
}
}
public interface UserService extends IService {
PageVo queryUserByPage(PageQuery query);
}
@Autowired
private UserMapper userMapper;
@Override
public PageVo queryUserByPage(PageQuery query) {
// mapper.selectPage() 都是可以的
Page page=Page.of(query.getPageNo(),query.getPageSize());
if (!StrUtil.isBlank(query.getSortBy())){
page.addOrder(new OrderItem(query.getSortBy(),query.getIsAsc()));
}
page=userMapper.selectPage(page,null);
Long pages=page.getPages();
Long total=page.getTotal();
List list=page.getRecords();
PageVo pageVo=new PageVo();
pageVo.setPages(pages);
pageVo.setTotal(total);
pageVo.setList(list);
if (CollUtil.isEmpty(list)){
//没有数据直接返回
return new PageVo(page.getTotal(),page.getPages(), Collections.emptyList());
}else {
//转换Vo的方法
List userVos= BeanUtil.copyToList(list,UserVo.class);
return new PageVo(page.getTotal(),page.getPages(), userVos);
}
}
localhost:8081/users/page
{
"pageNo":"1",
"pageSize":"5",
"sortBy":"username",
"isAsc":"false"
}
{
"total": 100005,
"pages": 20001,
"list": [
{
"id": 1674613593516396800,
"username": "赵天",
"info": {
"age": 20,
"intro": "伏地魔",
"gender": "female"
},
"status": "NORMAL",
"balance": 2000
},
{
"id": 1674613593516396800,
"username": "赵六99999",
"info": {
"age": 99999,
"intro": "99999伏地魔",
"gender": "female"
},
"status": "NORMAL",
"balance": 2000
},
{
"id": 1674613593516396800,
"username": "赵六99998",
"info": {
"age": 99998,
"intro": "99998伏地魔",
"gender": "female"
},
"status": "NORMAL",
"balance": 2000
},
{
"id": 1674613593516396800,
"username": "赵六99997",
"info": {
"age": 99997,
"intro": "99997伏地魔",
"gender": "female"
},
"status": "NORMAL",
"balance": 2000
},
{
"id": 1674613593516396800,
"username": "赵六99996",
"info": {
"age": 99996,
"intro": "99996伏地魔",
"gender": "female"
},
"status": "NORMAL",
"balance": 2000
}
]
}
但是此时的枚举不是我们需要的类型
{
"id": 2,
"username": "Rose",
"info": {
"age": 19,
"intro": "青涩少女",
"gender": "female"
},
"status": "NORMAL",
"balance": 300
},
在原先的枚举类上加上对应的 @JsonValue注解
//用户状态信息
@AllArgsConstructor
@Getter
public enum UserStatus {
NORMAL(1,"正常"),
FREEZE(2,"冻结");
@EnumValue
private final int value;
@JsonValue
private final String desc;
}
此时返回的内容就是下面的内容
此时把 @JsonValue注解加载desc上
{
"id": 3,
"username": "Hope",
"info": {
"age": 25,
"intro": "上进青年",
"gender": "male"
},
"status": "正常",
"balance": 99800
},
要是在value上加上对应的注解的话返回的就是下面的格式的内容
//用户状态信息
@AllArgsConstructor
@Getter
public enum UserStatus {
NORMAL(1,"正常"),
FREEZE(2,"冻结");
@EnumValue
@JsonValue
private final int value;
// @JsonValue
private final String desc;
}
{
"id": 1,
"username": "Jack",
"info": {
"age": 20,
"intro": "佛系青年",
"gender": "male"
},
"status": 2,
"balance": 0
},
封装分页
public Page getPage(String defaultSort, Boolean defaultIsAsc){
//分页插件
Page p=new Page(pageNo,pageSize);
if (!StrUtil.isBlank(sortBy)){
//排序条件
p.addOrder(new OrderItem(sortBy,isAsc));
}else { //可以不设置排序可以设置默认的排序
//默认排序
p.addOrder(new OrderItem(defaultSort,defaultIsAsc));
}
return p;
}
}