【Java从零到架构师第③季】【46】SpringBoot-MyBatisPlus_MyBatisGenerator


持续学习&持续更新中…

守破离


【Java从零到架构师第③季】【46】SpringBoot-MyBatisPlus_MyBatisGenerator

MyBatis-Plus

https://www.mybatis-plus.com/

在这里插入图片描述

HelloWorld

在这里插入图片描述

	<dependency>
	    <groupId>com.baomidou</groupId>
	    <artifactId>mybatis-plus-boot-starter</artifactId>
	    <version>3.4.1</version>
	</dependency>
mybatis-plus:
  type-aliases-package: programmer.lp.jk.pojo
  global-config:
    db-config:
      id-type: auto # 主键自增
  # mapper-locations的默认配置
  # mapper-locations: classpath*:/mapper/**/*.xml

条件、分页查询

MyBatisPlusConfig:

@Configuration
@MapperScan("programmer.lp.jk.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor innerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        // 当页数超过总页数时,自动跳回到第1页
        innerInterceptor.setOverflow(true);
        interceptor.addInnerInterceptor(innerInterceptor);
        return interceptor;
    }

    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }
}

Query Model:

@Data
public class PageQuery<T> {
    private static final int MIN_SIZE = 1;
    private static final int DEFAULT_SIZE = 10;
    private long size;
    private long no;
    private List<T> data;

    public long getSize() {
        return size < MIN_SIZE ? DEFAULT_SIZE : size;
    }

    public long getNo() {
        return no < MIN_SIZE ? MIN_SIZE : no;
    }
}
@EqualsAndHashCode(callSuper = true)
@Data
public class KeywordQuery<T> extends PageQuery<T> {
    private String keyword;
}
@EqualsAndHashCode(callSuper = true)
@Data
public class DictTypeQuery extends KeywordQuery<DictType> {
    private long total;
    private long pages;
}

查询业务:

@Service
@Transactional
public class DictTypeServiceImpl extends ServiceImpl<DictTypeMapper, DictType> implements DictTypeService {
    @Autowired
    private DictTypeMapper mapper;

    @Override
    public void list(DictTypeQuery query) {
        final String keyword = query.getKeyword();
        LambdaQueryWrapper<DictType> wrapper = new LambdaQueryWrapper<>();
        // 按照关键字查询
        if (!StringUtils.isEmpty(keyword)) {
            wrapper.like(DictType::getName, keyword).or()
                    .like(DictType::getIntro, keyword).or()
                    .like(DictType::getValue, keyword);
        }
        // 分页查询
        Page<DictType> page = new Page<>(query.getNo(), query.getSize());
        mapper.selectPage(page, wrapper);
        query.setData(page.getRecords());
        query.setPages(page.getPages());
        query.setTotal(page.getTotal());
    }
}

Controller:

@Controller
@RequestMapping("/dictTypes")
public class DictTypeController {
    @Autowired
    private DictTypeService service;

    @GetMapping("/list")
    public String list(DictTypeQuery query, Model model) {
        service.list(query);
        model.addAttribute("query", query);
        return "pages/dictType";
    }
}

浏览器客户端使用:

<form id="search-form" action="${ctx}/dictTypes/list">
    <input type="hidden" name="no" value="${query.no}">
    <input type="hidden" name="size" value="${query.size}">
    <input type="text" name="keyword" value="${query.keyword!}"
       placeholder="名称、值、简介"/>
</form>
 <#list query.data as item>
     <tr>
         <td>${item.name}</td>
         <td>${item.value}</td>
         <td>${item.intro!}</td>
     </tr>
 </#list>
 <div>
    <label>
        显示
        <select name="sizex" class="form-control form-control-sm">
            <option value="5">5</option>
            <option value="10">10</option>
            <option value="25">25</option>
            <option value="50">50</option>
            <option value="100">100</option>
        </select></label>
    ,共${query.pages}页,共${query.total}条
<#--        ,共${10}页,共${10}条-->
</div>

<script>
	// 搜索表单
	const $searchForm = $('#search-form')
	// 搜索表单 - size
	const $hiddenSize = $searchForm.find('[name=size]')
	// 搜索表单 - no
	const $hiddenPage = $searchForm.find('[name=no]')
	// 搜索表单 - 搜索按钮
	const $searchBtn = $searchForm.find('#search-btn')
	$searchBtn.click(() => {
	    $hiddenPage.val(1)
	    $searchForm.submit()
	})
	
	// 监听size改变—写法1
	const $selectSize = $('[name=sizex]')
	$selectSize.change(() => {
	    window.location.href = '${ctx}/dictTypes/list?size=' + $selectSize.val()
	        + "&keyword=" + $('[name=keyword]').val()
	})
	$selectSize.val(${query.size})

	// 监听size改变—写法2
	const $selectSize = $('[name=sizex]')
	$selectSize.change(() => {
	    $hiddenSize.val($selectSize.val())
	    $hiddenPage.val(1)
	    $searchForm.submit()
	})
	$selectSize.val(${query.size})

</script>

前端处理分页信息:

在这里插入图片描述

<!-- Bootstrap Core JavaScript -->
<script src="${ctx}/assets/libs/popper/popper.min.js"></script>
<script src="${ctx}/assets/libs/bootstrap/bootstrap.min.js"></script>
<!-- Bootstrap 分页插件 -->
<script src="${ctx}/assets/libs/bootstrap/bootstrap-paginator.min.js"></script>


<ul class="pagination">
</ul>
// 处理分页信息
$('ul.pagination').bootstrapPaginator({
    bootstrapMajorVersion: 3,
    currentPage: ${query.no},
    totalPages: ${query.pages},
    onPageClicked: (e1, e2, type, page) => {
        // 如果是当前页,直接返回
        if (page === ${query.no}) return
        $hiddenPage.val(page)
        $searchForm.submit()
    }
})

po自动生成—MyBatisGenerator

http://mybatis.org/generator/

在这里插入图片描述

注意:建议将MyBatis-Generator自动生成目录设置为src/test目录下,而不是src/main目录下,防止自己写好的src/main下的东西被覆盖。

注意:把自动生成的、不需要的Mapper和XML删掉,只需要保留po即可,因为数据库SQL语句还得是自己写的比较放心。

pom.xml:

    <build>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <configurationFile>src/test/resources/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.49</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

generatorConfig.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="default" targetRuntime="MyBatis3Simple">
        <commentGenerator>
            <!-- 去除所有注释 -->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <!-- 数据库连接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/jiakao?serverTimezone=Asia/Shanghai"
                        userId="root" password="root"/>

        <!-- Model的位置 -->
        <javaModelGenerator targetPackage="programmer.lp.jk.pojo.po"
                            targetProject="src/test/java"/>

        <!-- XML的位置 -->
        <sqlMapGenerator targetPackage="programmer.lp.jk.mapper"
                         targetProject="src/test/resources"/>

        <!-- Mapper的位置  -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="programmer.lp.jk.mapper"
                             targetProject="src/test/java"/>

        <!-- %代表所有表 -->
        <table tableName="%"/>
        <!-- <table tableName="dict_type"/> -->
    </context>
</generatorConfiguration>

逻辑删除

  • 物理删除:真正从数据库中删除了,永久消失。

  • 逻辑删除(假删除、软删除):数据还在数据库中,只是对用户来说,数据被删掉了。

  • 逻辑删除的实现:在需要实现逻辑删除的表中增加一个字段来标识数据是否被删除。

在这里插入图片描述

在这里插入图片描述

数据库建表语句:

# db: logic_delete
create table user
(
	id int unsigned auto_increment
		primary key,
	name varchar(15) default '' not null,
	deleted tinyint unsigned default 0 not null comment '1是被删除,0是未删除',
	constraint user_name_uindex
		unique (name)
);

依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>TestLogicDelete</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <druid.version>1.2.1</druid.version>
        <mybatis-plus.version>3.4.1</mybatis-plus.version>
        <springfox.version>3.0.0</springfox.version>
        <swagger-models.version>1.6.2</swagger-models.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- 数据库 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>

        <!-- 接口文档 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>${springfox.version}</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>${swagger-models.version}</version>
        </dependency>

        <!-- debug阶段 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>logic_delete</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

SpringBoot配置:

server:
  port: 9999

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/logic_delete?serverTimezone=GMT%2B8
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
  jackson:
    default-property-inclusion: non_null

mybatis-plus:
  global-config:
    db-config:
      id-type: auto
      # 全局配置
      # 逻辑删除字段
      logic-delete-field: deleted
      # 代表已删除的字段值
      logic-delete-value: 1
      # 代表未删除的字段值
      logic-not-delete-value: 0

logging:
  level:
    com.mj: debug

PO:

@Data
@ApiModel("用户")
public class User {
    @ApiModelProperty("id")
    private Long id;

    @ApiModelProperty("姓名")
    private String name;

    @ApiModelProperty(hidden = true)
    // 逻辑删除的局部配置
    // @TableLogic(value = "0", delval = "1")
    // 不要查询这个字段
    @TableField(select = false)
    private Short deleted;
}

Mapper(Dao):

public interface UserMapper extends BaseMapper<User> {
}

Service:

public interface UserService extends IService<User> {
}

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

Controller:

@RestController
@RequestMapping("/users")
@Api(tags = "用户")
public class UserController {
    @Autowired
    private UserService service;

    @GetMapping("/list")
    @ApiOperation("查询所有")
    public DataJsonVo<List<User>> list() {
        return new DataJsonVo<>(service.list());
    }

    @PostMapping("/save")
    @ApiOperation("添加或更新")
    public JsonVo save(User user) {
        JsonVo jsonVo = new JsonVo();
        jsonVo.setMsg(service.saveOrUpdate(user) ? "保存成功" : "保存失败");
        return jsonVo;
    }

    @PostMapping("/remove")
    @ApiOperation("删除")
    public JsonVo remove(Long id) {
        JsonVo jsonVo = new JsonVo();
        jsonVo.setMsg(service.removeById(id) ? "删除成功" : "删除失败");
        return jsonVo;
    }
    
    @PostMapping("/json")
    @ApiOperation("测试")
    public DataJsonVo<User> json(@RequestBody User user) {
        return new DataJsonVo<>(user);
    }

}

注意

  • Mapper(以前的DAO)更接近数据库,因此Mapper中方法的命名更接近数据库的SQL语句关键字:
    • mapper.insert();
    • mapper.delete();
    • mapper.update();
    • mapper.select();
  • Service更接近业务,因此Service的方法命名更贴近业务:
    • service.save();
    • service.remove();
    • service.update();
    • service.list();
  • 以后自己写项目,也推荐使用这种写法。

参考

小码哥-李明杰: Java从0到架构师③进阶互联网架构师.


本文完,感谢您的关注支持!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值