Spring boot + mybatis plus to implement CRUD common simple version

Posted by t_galan on Tue, 05 Oct 2021 20:05:00 +0200

Mybatis Plus

Today's goal:

  • Understand the features of mybatisplus
  • Get started with mybatisplus
  • Be able to master the common annotations of mybatisplus
  • Be able to master the common additions, deletions, modifications and queries of mybatisplus
  • Be able to master mybatis plus automatic code generation

1 MybatisPlus overview

MyBatis plus (MP for short) is an enhancement tool for MyBatis. On the basis of MyBatis, it only makes enhancements and does not change. It is born to simplify development and improve efficiency.

Official website: https://mybatis.plus/ Or https://mp.baomidou.com/

edition

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.4.2</version>
</dependency>

2 quick start

SpringBoot integrates mybatis plus and implements the query function according to Id.

1,Database environment preparation
2,establish SpringBoot Engineering, introduction MyBatis-Plus Scenario dependency
3,to write DataSource Related configuration
4,to write mapper
5,test

2.1 database environment preparation

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for tb_user  No self increase
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
  `id` bigint(20) NOT NULL,
  `user_name` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `t_name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of tb_user
-- ----------------------------
BEGIN;
INSERT INTO `tb_user` VALUES (1, 'Zhao Yishang', '123456', 'zys', 19, 'zys@itcast.cn');
INSERT INTO `tb_user` VALUES (2, 'Qian Erbai', '123456', 'qes', 18, 'qes@itcast.cn');
INSERT INTO `tb_user` VALUES (3, 'Sun Sanzao', '123456', 'ssh', 20, 'ssh@itcast.cn');
INSERT INTO `tb_user` VALUES (4, 'Li sicui', '123456', 'lsc', 20, 'lsc@itcast.cn');
INSERT INTO `tb_user` VALUES (5, 'Zhou Wushu', '123456', 'zws', 20, 'zws@itcast.cn');
INSERT INTO `tb_user` VALUES (6, 'Wu liupo', '123456', 'wlp', 21, 'wlp@itcast.cn');
INSERT INTO `tb_user` VALUES (7, 'Zheng qimie', '123456', 'zqm', 22, 'zqm@itcast.cn');
INSERT INTO `tb_user` VALUES (8, 'Wang bashui', '123456', 'wbs', 22, 'wbs@itcast.cn');
INSERT INTO `tb_user` VALUES (9, 'zhang wuji', '123456', 'zwj', 25, 'zwj@itcast.cn');
INSERT INTO `tb_user` VALUES (10, 'Zhao Min', '123456', 'zm', 26, 'zm@itcast.cn');
INSERT INTO `tb_user` VALUES (11, 'Zhao ershan', '123456', 'zes', 25, 'zes@itcast.cn');
INSERT INTO `tb_user` VALUES (12, 'Zhao Sanshan', '123456', 'zss1', 28, 'zss1@itcast.cn');
INSERT INTO `tb_user` VALUES (13, 'Zhao sishang', '123456', 'zss2', 29, 'zss2@itcast.cn');
INSERT INTO `tb_user` VALUES (14, 'Zhao Wushang', '123456', 'zws', 39, 'zws@itcast.cn');
INSERT INTO `tb_user` VALUES (15, 'Zhao liushang', '123456', 'zls', 29, 'zls@itcast.cn');
INSERT INTO `tb_user` VALUES (16, 'Zhao qishang', '123456', 'zqs', 39, 'zqs@itcast.cn');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

2.2 create a project and introduce scenario dependency

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.10.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
  <java.version>1.8</java.version>
</properties>

<dependencies>
  <!-- mysql  drive-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.26</version>
  </dependency>
  <!-- lombok  ,Automatic generation get,Set method-->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <!--mybatisplus Start dependence-->
  <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
  </dependency>
</dependencies>

2.3 write DataSource related configuration

# datasource
spring:
  datasource:
    url: jdbc:mysql://192.168.200.150:3306/mp?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

2.4 coding

Entity class:

package com.itheima.sh.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @Description:
 * @Version: V1.0
 */
 /*
Common notes:
@Data :  Note: on the class, the get, set, equals, hashCode, canEqual, toString methods of the class are provided
@AllArgsConstructor :  Note: on a class, provide the full parameter structure of the class
@NoArgsConstructor :  Note: on a class, provide a parameterless structure of the class
@Setter :  Note on the attribute, the set method is provided
@Getter :  Note: on the property, the get method is provided
@EqualsAndHashCode :  Note: on the class, the corresponding equals and hashCode methods are provided
@Log4j/@Slf4j :  Note: on the class, the corresponding Logger object is provided, and the variable name is log
@Builder: Chain add attribute instead of set()
@Table*: Property, indicating pojos and database_ Corresponding, if the same, it can be omitted
 */
@TableName("tb_user") // Specify table name
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;

}

@TableName("tb_user"): if the table name of the database is consistent with the entity class, it can be omitted

Write mapper:

package com.itheima.sh.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.sh.pojo.User;
/**
 * To define Mapper using mp, you need to let the Mapper interface inherit the BaseMapper interface.
 */
public interface UserMapper extends BaseMapper<User> {
//crud  insert delete update select
}

Add @ MapperScan annotation to startup class

package com.itheima.sh;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.itheima.sh.mapper")
public class MpApplication {
    public static void main(String[] args) {
        SpringApplication.run(MpApplication.class, args);
    }
}

2.5 testing

package com.itheima.sh;

import com.itheima.sh.mapper.UserMapper;
import com.itheima.sh.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;
    /**
     * Query by id
     */
    @Test
    public void testSelectById() {
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }
}

3 CRUD

Mapper inherits BaseMapper in the starter program:

3.1 NEW

3.1.1 method analysis

3.1.2 testing

@Test
public void testInsert() {
  User user =
    User.builder()
    .userName("itheima")
    .name("itcast")
    .age(15)
    .email("itcast@itcast.cn")
    .password("111111")
    .build();
  int insert = userMapper.insert(user);
  System.out.println(insert);
}

3.1.3 primary key generation policy - @ TableId

Role: identify the primary key column of the database and the strategy for generating the primary key

Use: add the member attribute corresponding to the primary key of the entity class

Primary key generation strategy:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableId {

    /**
     * Field name (this value can be null)
     */
    String value() default "";

    /**
     * Primary key type
     * {@link IdType}  View IdType
     */
    IdType type() default IdType.NONE;   // The default is NONE
}

// IdType 
@Getter
public enum IdType {
    /**
     * Database ID self increment
     * <p>This type is invalid if ID self increment is set in the database</p>
     */
    AUTO(0),
    /**
     * This type has no primary key set (in the annotation, it is equal to follow the global, and the global value is equal to INPUT)
     */
    NONE(1),
    /**
     * User input ID
     * <p>This type can be populated by registering its own auto fill plug-in</p>
     */
    INPUT(2),

    /* The following three types are automatically filled only when the inserted object ID is empty. */
    /**
     * Assign ID (the primary key type is number or string),
     * Default implementation class {@ link com. Baomidou. Mybatisplus. Core. Increment. Defaultidentifier generator} (snowflake algorithm)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * Assign UUID (the primary key type is string)
     * Default implementation class {@ link com. Baomidou. Mybatisplus. Core. Increment. Defaultidentifiergenerator} (UUID. Replace ("-", ""))
     */
    ASSIGN_UUID(4),
 
  // Omit part of the code
}

3.1.4 general column annotation - @ TableField

effect:

1) @ TableField("user_name") specifies the mapping relationship

The following cases can be omitted:

  • Same name
  • Database fields are divided by and entity class attribute names are hump names

2) Ignore the query of a field and insert @ TableField(exist = false)

3.1.5 specific use

/**
 * The attribute name of the entity class and the field name of the database are automatically mapped:
 *  1. Same name
 *  2. Database fields are divided by and entity class attribute names are hump names
 */

@TableName("tb_user")
@Data
public class User {


    //Set id generation strategy: AUTO database AUTO increment
    @TableId(type = IdType.AUTO)
    private Long id;
    //@TableField("user_name")
    private String userName;

    private String password;
  
    @TableField("t_name")
    private String name;
    private Integer age;
    private String email;

    //You do not want this value stored in the database
   // @TableField(exist = false)
   // private String address;

}

3.2 deletion

3.2.1 delete by id

 int count = userMapper.deleteById(8L);

3.2.2 batch deletion based on id set

 List ids = new ArrayList();
        ids.add(6);
        ids.add(7);

userMapper.deleteBatchIds(ids);

3.2.3 delete according to the map construction conditions

 Map<String, Object> map = new HashMap<>();

//delete from tb_user where user_name = ? and age = ?
map.put("user_name","itcast");
map.put("age","18");

userMapper.deleteByMap(map);

3.2.4 delete according to wrapper construction conditions

//1. Create query criteria builder
 QueryWrapper<User> wrapper = new QueryWrapper<>();
//2. Setting conditions
//delete from tb_user where user_name = ? and age = ?
wrpper.eq("userName","lisi")
			.gt("age","11");

userMapper.delete(wrapper);

3.3 update

@Test
public void testUpdateById() {
  User user = new User();
  user.setId(2L);
  user.setPassword("1111111");
  int count = userMapper.updateById(user);
}

4 query

4.1 paging query

Configure interceptor

package com.itheima.sh.config;

import com.baomidou.mybatisplus.annotation.DbType;
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;

/**
 * @Description:
 * @Version: V1.0
 */
@Configuration
public class MybatisPlusConfig {


    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);

        // After setting the requested page to be larger than the maximum page, true will be called back to the home page, false will continue to request, and the default is false
        // paginationInterceptor.setOverflow(false);
        // Set the maximum number of single page restrictions, 500 by default, - 1 unlimited
        paginationInterceptor.setMaxLimit(-1L);
        // Turn on the join optimization of count, only for some left join s
        interceptor.addInnerInterceptor(paginationInterceptor);
        return interceptor;
    }

}

query

/**
  * Paging query:
  *  1. Current page number: currentPage
  *  2. Number of items displayed per page: size
  *
  *  Note: an interceptor should be set for paging using mp!!!
*/
@Test
public void testSelectPage() {
  int current = 1;//Current page number
  int size = 2;//Number of displays per page
  IPage<User> page = new Page(current,size);
  userMapper.selectPage(page,null);

  List<User> records = page.getRecords();//Data of the current page
  long pages = page.getPages();//Total pages 2
  long total = page.getTotal();//Total records 4
  System.out.println(records);
  System.out.println(pages);
  System.out.println(total);
}

4.2 condition constructor query

/**
 * Basic comparison query
 *
 * Wrapper:
 *  1.QueryWrapper
 *      LambdaQueryWrapper
 *  2.UpdateWrapper
 *      LambdaUpdateWrapper
 *
 */

4.2.1 basic query

Specify query criteria through QueryWrapper

eq( ) :  be equal to =
ne( ) :  Not equal to <>
gt( ) :  greater than >
ge( ) :  Greater than or equal to  >=
lt( ) :  less than <
le( ) :  Less than or equal to <=
between ( ) :  BETWEEN Value 1 AND Value 2 
notBetween ( ) :  NOT BETWEEN Value 1 AND Value 2 
in( ) :  in
notIn( ) : not in
@Test
public void testWrapper1() throws Exception{

  QueryWrapper<User> wrapper = new QueryWrapper<>();

  // Encapsulate query criteria
  wrapper.like("user_name", "%injury%")
    .eq("password","123456")
    .in("age",19,25,29)
    .orderByDesc("age","id");   // Descending ascending: asc

  List<User> users = userMapper.selectList(wrapper);
  System.out.println(users);
}

4.2.2 logical query or

or( ) : Let's follow the next method or connect 
@Test
    public void testWrapper2(){
        //1. Create query criteria builder
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //2. Setting conditions
        wrapper.eq("user_name","lisi")
                .or()
                .lt("age",23)
                .in("name","Li Si","Wang Wu");
        /*
            select * from tb_user where user_name = ? or age < ? and name in (?,?)
         */
        List<User> users = userMapper.selectList(wrapper);
        System.out.println(users);
    }

4.2.3 fuzzy query like

like
notLike
likeLeft
likeRight
/**
     * Fuzzy query
     */
    @Test
    public void testWrapper3(){
        //1. Create query criteria builder
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //2. Setting conditions
        wrapper.likeLeft("user_name","zhang");
        /*
            SELECT id,user_name,password,name,age,email
             from tb_user
             where user_name like ?
             %zhang
         */
        List<User> users = userMapper.selectList(wrapper);
        System.out.println(users);
    }

4.2.4 Sorting Query

orderBy
orderByAsc
orderByDesc
@Test
    public void testWrapper4(){
        //1. Create query criteria builder
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //2. Setting conditions
        wrapper.eq("user_name","lisi")
                .or()
                .lt("age",23)
                .in("name","Li Si","Wang Wu")
                //.orderBy(true,true,"age")
                .orderByDesc("age");
        /*
            select * from tb_user where user_name = ? or age < ? and name in (?,?) order by age asc
         */
        List<User> users = userMapper.selectList(wrapper);
        System.out.println(users);
    }

4.2.5 select: specify the fields to query

@Test
    public void testWrapper5(){
        //1. Create query criteria builder
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //2. Setting conditions
        wrapper.eq("user_name","lisi")
                .or()
                .lt("age",23)
                .in("name","Li Si","Wang Wu")
                //.orderBy(true,true,"age")
                .orderByDesc("age")
                .select("id","user_name");
        /*
            select id,user_name from tb_user where user_name = ? or age < ? and name in (?,?) order by age asc
         */
        List<User> users = userMapper.selectList(wrapper);
        System.out.println(users);
    }

4.2.6 paging condition query

@Test
    public void testWrapper6(){

        int current = 1;//Current page number
        int size = 2;//Number of displays per page
        //1. Build paging object
        Page<User> page = new Page<>(current,size);
        //2. Build condition object
        QueryWrapper<User> wrapper = new QueryWrapper();
        wrapper.lt("age",23);
        userMapper.selectPage(page,wrapper);
        List<User> records = page.getRecords();
        long total = page.getTotal();
        long pages = page.getPages();
        System.out.println(records);
        System.out.println(total);//2
        System.out.println(pages);//1

    }

4.2.7 LambdaQueryWrapper

Objective: to eliminate hard coding in the code

@Test
public void testWrapper4() throws Exception{


  //        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
  LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery();

  //        wrapper.like("user_name", "% wound%")
  //                .eq("password","123456")
  //                .ge("age", 28)
  //                . between ("age", 29, 39); / / contains boundary values

  wrapper.like(User::getUserName, "%injury%")
    .eq(User::getPassword, "123456")
    .ge(User::getAge, 28)
    .between(User::getAge, 29, 39)
    .orderByDesc(User::getAge)
    .select(User::getId, User::getUserName);


  List<User> users = userMapper.selectList(wrapper);
  System.out.println(users);
}

4.2.8 condition deletion

/**
     * Condition deletion
     * @throws Exception
     */
@Test
public void testWrapper5() throws Exception{

  LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery().eq(User::getUserName, "Wu Dalang");
  int i = userMapper.delete(wrapper);
  System.out.println(i);
}

4.2.9 condition update

/**
     * Condition update
     * @throws Exception
     */
@Test
public void testWrapper6() throws Exception{

  /**
         * UPDATE tb_user SET t_name=? WHERE (id = ?)
         */
  // Parameter 1: latest value
  User user = new User();
  user.setUserName("Zhang Sanfeng");

  // Parameter 2: update condition
  LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery();
  wrapper.eq(User::getId, 15);


  int update = userMapper.update(user, wrapper);
  System.out.println(update);
}


/**
     * Condition update
     * @throws Exception
     */
@Test
public void testWrapper7() throws Exception{

  /**
         * UPDATE tb_user SET t_name=?, user_name=? WHERE (id = ?)
         */
  // Parameter 1: latest value
  // Parameter 2: update condition
  LambdaUpdateWrapper<User> wrapper = Wrappers.<User>lambdaUpdate();
  wrapper.eq(User::getId, 15)
    .set(User::getUserName, "Zhang Sanfeng 666")
    .set(User::getName,"zsf666");

  int update = userMapper.update(null, wrapper);
  System.out.println(update);
}

5 service encapsulation

In order to develop faster, mybatis plus encapsulates the business layer and directly provides relevant interfaces and implementation classes. When developing the business layer, we can inherit the interfaces and implementation classes provided by it to make the coding more efficient

- 1. Define interface inheritance IService
- 2. Define and implement class inheritance ServiceImpl<Mapper,Entity> Implement defined interfaces

Interface

public interface UserService extends IService<User> {
}

Implementation class encapsulation

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}

crud save remove update (list get query has no select)
Write the Controller and use PostMan to test

package com.itheima.sh.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.sh.pojo.User;
import com.itheima.sh.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @Description:
 * @Version: V1.0
 */
@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    UserService userService;


    @PostMapping
    public User add( @RequestBody User user) {
        userService.save(user);   // If saved successfully, the primary key will be automatically encapsulated on the User's primary key attribute
        return user;
    }

    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable("id") Long id) {
        return userService.removeById(id);
    }

    @PutMapping("/{id}")
    public boolean update(@PathVariable("id") Long id,@RequestBody User user) {
        return userService.update(user, Wrappers.<User>lambdaQuery().eq(User::getId, id));
    }


    @GetMapping("/{id}")
    public User findOne(@PathVariable("id") Long id) {
        return userService.getById(id);
    }


    @PostMapping("findList")
    public List<User> findList(@RequestBody User user) {

        LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery();

        if (user.getUserName()!=null && user.getUserName().length() > 0) {
            wrapper.like(User::getUserName, user.getUserName());
        }

        if (user.getAge() != null) {
            wrapper.eq(User::getAge, user.getAge());
        }

        List<User> list = userService.list(wrapper);
        return list;
    }


    @PostMapping("findPage/{page}/{size}")
    public Page<User> findPage(@PathVariable("page") Long current, @PathVariable("size") Long size,
                               @RequestBody User user) {

        LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery();

        if (user.getUserName()!=null && user.getUserName().length() > 0) {
            wrapper.like(User::getUserName, user.getUserName());
        }

        if (user.getAge() != null) {
            wrapper.eq(User::getAge, user.getAge());
        }
        Page<User> page = new Page<>(current,size);
        return userService.page(page,wrapper);
    }

}

6 reverse engineering - code generator

6.1 code generation description

When there is a new business implementation, we usually need to build the following information for the function implementation of the interface:

  • PO class

    Mapping of database tables and entity classes Java beans.

  • DAO layer

    The interface Mapper needs to be written, and the interface Mapper needs to inherit the BaseMapper interface in the MP.

  • Service layer

    Write the Service layer interface and implementation class. The business interface needs to inherit IService in MP, and the business implementation class needs to inherit ServiceImpl in MP and implement the business interface.

  • Controller layer

    Write the Controller and mark the relevant annotations in Spring MVC.

You can put it down from the above codes. The codes are all template. If you use manual copy and modification, it will be too annoying and inefficient. At this time, when the code generator is small, you can use the code generator to generate template codes, reduce the complexity of manual operation, and focus on business development to improve development efficiency.

AutoGenerator is the code generator of mybatis plus. Through AutoGenerator, you can quickly generate the code of Mapper interface, Entity class, Mapper XML, Service, Controller and other modules, which greatly improves the development efficiency.

6.2 code generation

The complete code has been provided in the import data

Or gitee open source link: https://gitee.com/jitheima/mp_generator.git

Full code:


Later, it will be used in the project. After it is generated here, you can copy the code to the corresponding directory for use. In the whole development stage of the dark horse headline project, the currently generated mapper and entity class are used.

7 MybatisX plug-in

MybatisX is a rapid development plug-in based on IDEA, which is born for efficiency.

Installation method: open IDEA, enter file - > Settings - > plugins - > Browse repositories, enter mybatisx to search and install.

Function:

  • Java and XML call back jump
  • Mapper method automatically generates XML

Topics: Spring Spring Boot ssh