MyBatis-Plus-Operaciones extendidas (3)

3. Extensión

Generación de código
Eliminación lógica
Procesador de enumeración
Procesador json Cifrado
de configuración
Complemento de paginación

3.1 Generación de código

https://blog.csdn.net/weixin_41957626/article/details/132651552

Descargue el complemento a continuación,
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
el rojo acaba de generarse.
Insertar descripción de la imagen aquí
Creo que no es tan fácil de usar como el oficial, la única ventaja es que las opciones marcadas se pueden entender claramente.

3.2 Eliminación lógica

En realidad no es una eliminación, es una operación de actualización, simplemente establezca el bit de bandera correspondiente en la bandera correspondiente.

En mp, los ajustes de configuración global se pueden usar para realizar la operación de eliminación lógica correspondiente de la misma manera que la eliminación lógica original.

La siguiente es la configuración global.

  global-config:
    db-config:
      logic-delete-field: flag #全局删除的实体的字段名
      logic-delete-value: 1 #逻辑删除值
      logic-not-delete-value: 0 #逻辑未删除的值

Tenga en cuenta que todas las tablas se basan en el siguiente formato.

Se puede configurar en los campos de la tabla especificada. Los campos para la eliminación lógica deben configurarse por separado.

Agregue campos desechados en la base de datos.
Insertar descripción de la imagen aquí
Probar la eliminación lógica de la dirección

 @Test
    void tes61(){
    
    
      boolean flag=  addressService.removeById(59L);
      System.out.println("删除的结果="+flag);
    }

Eliminar resultados

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

Insertar descripción de la imagen aquí
Al realizar la consulta en este momento, no se puede encontrar la consulta.

   @Test
    void tes62(){
        Address address=  addressService.getById(59L);
        System.out.println("address="+address);
    }

Resultados de la consulta

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

En este momento, no se puede encontrar el contenido que lógicamente estamos eliminando.

Configuraciones para tipos de campos de desecho en la base de datos

Puede ser en formato bit o tipo int.

  • Los métodos de visualización que utilizan estos dos métodos son diferentes.

Usando el tipo int,
Insertar descripción de la imagen aquí
lo que se muestra en la idea en este momento es 0 y 1. Hay un problema al que se debe prestar atención en el diseño del código: falso debe corresponder a 0 y 1 debe corresponder a verdadero.

El tipo de bit es similar, pero es diferente cuando se muestra directamente.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Necesitas escapar cuando usas bits.

  @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)

3.3 Procesador de enumeración

Los campos como el estado se pueden convertir utilizando los convertidores de estado correspondientes.

Los tipos de enumeración son tipos de datos más estándar que constantes.

    /**
     * 使用状态(1正常 2冻结)
     */
    private Integer status;

Al insertar desde una clase de enumeración, no se recomienda realizar llamadas indirectas cuando sea necesario. ¿Existe alguna forma de convertir directamente los tipos de enumeración?

mp originalmente nos ayudó a definir el procesador de tipo de enumeración correspondiente. Podemos simplemente llamarlo directamente.

La siguiente es la relación correspondiente entre los atributos de la clase original y la clase de enumeración.

Insertar descripción de la imagen aquí
Operaciones básicas

  • Definir una clase de enumeración
//用户状态信息
@AllArgsConstructor
@Getter
public enum UserStatus {
    NORMAL(1,"正常"),
    FREEZE(2,"冻结");
    @EnumValue
    private final int value;
    private final String desc;
}
  • Configure mp para configurar un procesador de tipo de enumeración
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
  • Modificar clase de entidad
//    private Integer status;
    private UserStatus status;
  • prueba
@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);
}
  • resultado
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

Insertar descripción de la imagen aquí

@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)

Procesador 3.4JSON

Cómo convertir una cadena json en un objeto de la clase correspondiente

Insertar descripción de la imagen aquí
El tipo de campo de información de la base de datos es json

Insertar descripción de la imagen aquí
Esto no es global. La capa inferior de MVC más utilizada es el procesador de tipo Jackson, que no es JSON.

  • Originalmente se utilizó el siguiente tipo de datos
    private Object info;
  • Ahora necesita cambiarlo al siguiente tipo de datos y agregar el procesador de tipo correspondiente
    @TableField(typeHandler = JacksonTypeHandler.class)
    private UserInfo info;
  • Crear una clase de entidad
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class UserInfo implements Serializable {
    private Integer age;
    private String intro;
    private String gender;
}

  • Realizar operaciones de consulta en este momento.
    @Test
    void tes65(){
        User user=userService.lambdaQuery()
                .eq(User::getUsername,"赵天").one();
        System.out.println(user.toString());
    }
  • Resultado: el valor de la información consultada en este momento es nulo.
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, <<BLOB>>, 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)

La razón de lo anterior es que no establecimos el valor de resultMap.

La solución más sencilla: configurar el mapeo automático.

@TableName(value ="user",autoResultMap = true)

En este punto aparece el valor de la consulta.

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, <<BLOB>>, 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)

O utilice su propio método designado

@TableName(value ="user",resultMap = "BaseResultMap")
<resultMap id="BaseResultMap" type="com.lxz.demo.domain.User">
    <id property="id" column="id" jdbcType="BIGINT"/>
    <result property="username" column="username" jdbcType="VARCHAR"/>
    <result property="password" column="password" jdbcType="VARCHAR"/>
    <result property="phone" column="phone" jdbcType="VARCHAR"/>
    <result property="info" column="info" jdbcType="OTHER" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
    <result property="status" column="status" jdbcType="INTEGER"/>
    <result property="balance" column="balance" jdbcType="INTEGER"/>
    <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
    <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
</resultMap>

3.5 Configurar el cifrado

De forma predeterminada, mp proporciona una herramienta de cifrado que utiliza el algoritmo AES para cifrar información confidencial en la configuración.

Generar cuenta y contraseña cifradas

    @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);
    }

Los siguientes son los números de cuenta y contraseñas cifrados generados, así como las claves utilizadas para el cifrado y descifrado:

randomKey=19cb291382b38782
username=ebMDrqWwkpNR9jkM+2x5Iw==
password=ebMDrqWwkpNR9jkM+2x5Iw==

Agregue la configuración cifrada al archivo de configuración

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

Agregue los parámetros de inicio correspondientes al iniciar

  • Si es una prueba unitaria, configure el siguiente contenido a continuación
@SpringBootTest(args = "--mpw.key=19cb291382b38782")
  • Si no es una prueba unitaria, debe configurar el siguiente contenido

Insertar descripción de la imagen aquí
código de prueba

  @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, <<BLOB>>, 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)

Esto indica que la contraseña descifrada fue exitosa.

4. Función de complemento

La esencia es la función interceptora.

4.1 Complemento de paginación

El siguiente es contenido común:
Insertar descripción de la imagen aquí
escribir clases de configuración

@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;
    }
}

Pruebe la paginación simple

 @Test
    void tes65(){
        //分页参数
        Integer pageNum=1;
        Integer pageSize=10;
        //分页对象
        Page<User> page=new Page<User>(pageNum, pageSize);

        //排序
        page.addOrder(new OrderItem("username",false));
        //其他参数
         page=userService.page(page);
        Long count=page.getTotal();
        List<User> result=page.getRecords();
        System.out.println("count="+count);
        result.forEach(System.out::println);
    }

Insertar descripción de la imagen aquí

 //排序 这个是升序
        page.addOrder(new OrderItem("username",true));

Hay condiciones de consulta.

 page=userService.page(page,null);

4.2 Caso de paginación

Contenido de la interfaz:

Insertar descripción de la imagen aquí
Entidad de finalización:

  • Solicitar parámetros
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<T> implements Serializable {

    private Long total;
    private Long pages;
    /*
    * 采用泛型是最好的
    * */
    private List<T> list;

}

  • Parámetros de retorno
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;


}

  • Clase de interfaz
@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/page")
    public PageVo<UserVo> queryUserByPage(@RequestBody  PageQuery query){
        return userService.queryUserByPage(query);
    }

}

o

La diferencia es que el método de inyección es diferente.

@RestController
@RequestMapping("/users2")
@RequiredArgsConstructor
public class UserController2 {


    private final UserService userService;

    @PostMapping("/page")
    public PageVo<UserVo> queryUserByPage(@RequestBody  PageQuery query){
        return userService.queryUserByPage(query);
    }
}

  • capa de servicio
public interface UserService extends IService<User> {

    PageVo<UserVo> queryUserByPage(PageQuery query);
}

 @Autowired
    private UserMapper userMapper;

    @Override
    public PageVo<UserVo> queryUserByPage(PageQuery query) {
        // mapper.selectPage() 都是可以的
        Page<User> 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<User> 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<UserVo> userVos= BeanUtil.copyToList(list,UserVo.class);
            return new PageVo(page.getTotal(),page.getPages(), userVos);
        }
    }
  • interfaz de prueba
localhost:8081/users/page

{
    "pageNo":"1",
    "pageSize":"5",
    "sortBy":"username",
    "isAsc":"false"
}
  • resultado de búsqueda
{
	"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
		}
	]
}

Pero la enumeración en este momento no es el tipo que necesitamos.

{
			"id": 2,
			"username": "Rose",
			"info": {
				"age": 19,
				"intro": "青涩少女",
				"gender": "female"
			},
			"status": "NORMAL",
			"balance": 300
		},

Agregue la anotación @JsonValue correspondiente a la clase de enumeración original

//用户状态信息
@AllArgsConstructor
@Getter
public enum UserStatus {
    NORMAL(1,"正常"),
    FREEZE(2,"冻结");
    @EnumValue
    private final int value;
    @JsonValue
    private final String desc;
}

El contenido devuelto en este momento es el siguiente contenido

En este momento, cargue la anotación @JsonValue en desc.

	{
			"id": 3,
			"username": "Hope",
			"info": {
				"age": 25,
				"intro": "上进青年",
				"gender": "male"
			},
			"status": "正常",
			"balance": 99800
		},

Si agrega la anotación correspondiente al valor, se devolverá el contenido en el siguiente formato.

//用户状态信息
@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
		},

4.3 Simplificar la operación de 4.2

paginación de encapsulación

    public<T> Page<T> getPage(String defaultSort, Boolean defaultIsAsc){
        //分页插件
        Page<T> p=new Page<T>(pageNo,pageSize);
        if (!StrUtil.isBlank(sortBy)){
            //排序条件
            p.addOrder(new OrderItem(sortBy,isAsc));
        }else { //可以不设置排序可以设置默认的排序
            //默认排序
            p.addOrder(new OrderItem(defaultSort,defaultIsAsc));
        }
        return p;
    }

}

Supongo que te gusta

Origin blog.csdn.net/weixin_41957626/article/details/132792640
Recomendado
Clasificación