前言
上次介紹了Spring Boot中Mybatis的簡單整合爬虱,本篇深入來結(jié)合通用Mapper碎浇、Mybatis Geneator以及分頁P(yáng)ageHelper來打造適合企業(yè)開發(fā)的模板框架。
正文
項(xiàng)目框架還是跟上一篇一樣使用Spring Boot的ace后端模板乒裆,不過最近在使用vue套利,所以前端引用了vue進(jìn)來改寫,代碼變得更加簡潔缸兔。
項(xiàng)目配置:
Spring Boot: 1.5.9.RELEASE
Maven: 3.5
Java: 1.8
Thymeleaf: 3.0.7.RELEASE
Vue.js: v2.5.11
數(shù)據(jù)源依賴
這里我們還是使用阿里巴巴的druid來當(dāng)數(shù)據(jù)庫連接池日裙,發(fā)現(xiàn)這個(gè)有對應(yīng)的監(jiān)控界面,我們可以開啟惰蜜。
druid官方文檔:https://github.com/alibaba/druid/wiki/常見問題
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.19</version>
</dependency>
對應(yīng)的application.properties配置:
## 數(shù)據(jù)庫訪問配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = root
# 下面為連接池的補(bǔ)充設(shè)置,應(yīng)用到上面所有數(shù)據(jù)源中
# 初始化大小受神,最小抛猖,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置獲取連接等待超時(shí)的時(shí)間
spring.datasource.maxWait=60000
# 配置間隔多久才進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接鼻听,單位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一個(gè)連接在池中最小生存的時(shí)間财著,單位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打開PSCache,并且指定每個(gè)連接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置監(jiān)控統(tǒng)計(jì)攔截的filters撑碴,去掉后監(jiān)控界面sql無法統(tǒng)計(jì)撑教,'wall'用于防火墻
spring.datasource.filters=stat,wall,log4j
# 合并多個(gè)DruidDataSource的監(jiān)控?cái)?shù)據(jù)
#spring.datasource.useGlobalDataSourceStat=true
對應(yīng)的bean配置:
package com.dudu.config;
/**
* Druid配置
*
* @author dudu
* @date 2017-12-11 0:00
*/
@Configuration
public class DruidConfig {
private Logger logger = LoggerFactory.getLogger(DruidConfig.class);
@Value("${spring.datasource.url:#{null}}")
private String dbUrl;
@Value("${spring.datasource.username: #{null}}")
private String username;
@Value("${spring.datasource.password:#{null}}")
private String password;
@Value("${spring.datasource.driverClassName:#{null}}")
private String driverClassName;
@Value("${spring.datasource.initialSize:#{null}}")
private Integer initialSize;
@Value("${spring.datasource.minIdle:#{null}}")
private Integer minIdle;
@Value("${spring.datasource.maxActive:#{null}}")
private Integer maxActive;
@Value("${spring.datasource.maxWait:#{null}}")
private Integer maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}")
private Integer timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}")
private Integer minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery:#{null}}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle:#{null}}")
private Boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow:#{null}}")
private Boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn:#{null}}")
private Boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements:#{null}}")
private Boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}")
private Integer maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters:#{null}}")
private String filters;
@Value("{spring.datasource.connectionProperties:#{null}}")
private String connectionProperties;
@Bean
@Primary
public DataSource dataSource(){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
//configuration
if(initialSize != null) {
datasource.setInitialSize(initialSize);
}
if(minIdle != null) {
datasource.setMinIdle(minIdle);
}
if(maxActive != null) {
datasource.setMaxActive(maxActive);
}
if(maxWait != null) {
datasource.setMaxWait(maxWait);
}
if(timeBetweenEvictionRunsMillis != null) {
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
if(minEvictableIdleTimeMillis != null) {
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
if(validationQuery!=null) {
datasource.setValidationQuery(validationQuery);
}
if(testWhileIdle != null) {
datasource.setTestWhileIdle(testWhileIdle);
}
if(testOnBorrow != null) {
datasource.setTestOnBorrow(testOnBorrow);
}
if(testOnReturn != null) {
datasource.setTestOnReturn(testOnReturn);
}
if(poolPreparedStatements != null) {
datasource.setPoolPreparedStatements(poolPreparedStatements);
}
if(maxPoolPreparedStatementPerConnectionSize != null) {
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
}
if(connectionProperties != null) {
datasource.setConnectionProperties(connectionProperties);
}
List<Filter> filters = new ArrayList<>();
filters.add(statFilter());
filters.add(wallFilter());
datasource.setProxyFilters(filters);
return datasource;
}
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
//控制臺管理用戶,加入下面2行 進(jìn)入druid后臺就需要登錄
//servletRegistrationBean.addInitParameter("loginUsername", "admin");
//servletRegistrationBean.addInitParameter("loginPassword", "admin");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("profileEnable", "true");
return filterRegistrationBean;
}
@Bean
public StatFilter statFilter(){
StatFilter statFilter = new StatFilter();
statFilter.setLogSlowSql(true); //slowSqlMillis用來配置SQL慢的標(biāo)準(zhǔn)醉拓,執(zhí)行時(shí)間超過slowSqlMillis的就是慢伟姐。
statFilter.setMergeSql(true); //SQL合并配置
statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值為3000,也就是3秒亿卤。
return statFilter;
}
@Bean
public WallFilter wallFilter(){
WallFilter wallFilter = new WallFilter();
//允許執(zhí)行多條SQL
WallConfig config = new WallConfig();
config.setMultiStatementAllow(true);
wallFilter.setConfig(config);
return wallFilter;
}
}
mybatis相關(guān)依賴
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!--通用mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.1.5</version>
</dependency>
<!--pagehelper 分頁插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<dependencies>
<!--配置這個(gè)依賴主要是為了等下在配置mybatis-generator.xml的時(shí)候可以不用配置classPathEntry這樣的一個(gè)屬性愤兵,避免代碼的耦合度太高-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.4.0</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<phase>package</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<!--允許移動生成的文件 -->
<verbose>true</verbose>
<!-- 是否覆蓋 -->
<overwrite>true</overwrite>
<!-- 自動生成的配置 -->
<configurationFile>src/main/resources/mybatis-generator.xml</configurationFile>
</configuration>
</plugin>
</plugins>
</build>
上面引入了mybatis相關(guān)的一些依賴以及generator的配置,這里generator配置文件指向
src/main/resources/mybatis-generator.xml文件排吴,具體一會貼出秆乳。
對應(yīng)的application.properties配置:
#指定bean所在包
mybatis.type-aliases-package=com.dudu.domain
#指定映射文件
mybatis.mapperLocations=classpath:mapper/*.xml
#mapper
#mappers 多個(gè)接口時(shí)逗號隔開
mapper.mappers=com.dudu.util.MyMapper
mapper.not-empty=false
mapper.identity=MYSQL
#pagehelper
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
通用Mapper配置
通用Mapper都可以極大的方便開發(fā)人員,對單表封裝了許多通用方法,省掉自己寫增刪改查的sql。
通用Mapper插件網(wǎng)址:https://github.com/abel533/Mapper
package com.dudu.util;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
/**
* 繼承自己的MyMapper
*
* @author
* @since 2017-06-26 21:53
*/
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
//FIXME 特別注意屹堰,該接口不能被掃描到肛冶,否則會出錯
}
這里實(shí)現(xiàn)一個(gè)自己的接口,繼承通用的mapper,關(guān)鍵點(diǎn)就是這個(gè)接口不能被掃描到扯键,不能跟dao這個(gè)存放mapper文件放在一起淑趾。
最后在啟動類中通過MapperScan注解指定掃描的mapper路徑:
package com.dudu;
@SpringBootApplication
//啟注解事務(wù)管理
@EnableTransactionManagement // 啟注解事務(wù)管理,等同于xml配置方式的 <tx:annotation-driven />
@MapperScan(basePackages = "com.dudu.dao", markerInterface = MyMapper.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
MyBatis Generator配置
這里配置一下上面提到的mybatis-generator.xml文件,該配置文件用來自動生成表對應(yīng)的Model,Mapper以及xml,該文件位于src/main/resources
下面
Mybatis Geneator 詳解: http://blog.csdn.net/isea533/article/details/42102297
<?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>
<!--加載配置文件忧陪,為下面讀取數(shù)據(jù)庫信息準(zhǔn)備-->
<properties resource="application.properties"/>
<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="com.dudu.util.MyMapper" />
<!--caseSensitive默認(rèn)false扣泊,當(dāng)數(shù)據(jù)庫表名區(qū)分大小寫時(shí),可以將該屬性設(shè)置為true-->
<property name="caseSensitive" v
alue="true"/>
</plugin>
<!-- 阻止生成自動注釋 -->
<commentGenerator>
<property name="javaFileEncoding" value="UTF-8"/>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--數(shù)據(jù)庫鏈接地址賬號密碼-->
<jdbcConnection driverClass="${spring.datasource.driver-class-name}"
connectionURL="${spring.datasource.url}"
userId="${spring.datasource.username}"
password="${spring.datasource.password}">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--生成Model類存放位置-->
<javaModelGenerator targetPackage="com.dudu.domain" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--生成映射文件存放位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!--生成Dao類存放位置-->
<!-- 客戶端代碼嘶摊,生成易于使用的針對Model對象和XML配置文件 的代碼
type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper對象
type="XMLMAPPER",生成SQLMap XML文件和獨(dú)立的Mapper接口
-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.dudu.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--生成對應(yīng)表及類名
去掉Mybatis Generator生成的一堆 example
-->
<table tableName="LEARN_RESOURCE" domainObjectName="LearnResource" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
<generatedKey column="id" sqlStatement="Mysql" identity="true"/>
</table>
</context>
</generatorConfiguration>
其中延蟹,我們通過<properties resource="application.properties"/>
引入了配置文件,這樣下面指定數(shù)據(jù)源的時(shí)候不用寫死叶堆。
其中tk.mybatis.mapper.generator.MapperPlugin很重要阱飘,用來指定通用Mapper對應(yīng)的文件,這樣我們生成的mapper都會繼承這個(gè)通用Mapper
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="com.dudu.util.MyMapper" />
<!--caseSensitive默認(rèn)false虱颗,當(dāng)數(shù)據(jù)庫表名區(qū)分大小寫時(shí)沥匈,可以將該屬性設(shè)置為true-->
<property name="caseSensitive" value="true"/>
</plugin>
這樣就可以通過mybatis-generator插件生成對應(yīng)的文件啦
如果不是IDEA開發(fā)環(huán)境也可以直接通過命令:mvn mybatis-generator:generate
自動生成的文件如下圖所示
腳本初始化
CREATE DATABASE /*!32312 IF NOT EXISTS*/`spring` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `spring`;
DROP TABLE IF EXISTS `learn_resource`;
CREATE TABLE `learn_resource` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`author` varchar(20) DEFAULT NULL COMMENT '作者',
`title` varchar(100) DEFAULT NULL COMMENT '描述',
`url` varchar(100) DEFAULT NULL COMMENT '地址鏈接',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1029 DEFAULT CHARSET=utf8;
insert into `learn_resource`(`id`,`author`,`title`,`url`) values (999,'官方SpriongBoot例子','官方SpriongBoot例子','https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples');
insert into `learn_resource`(`id`,`author`,`title`,`url`) values (1000,'龍果學(xué)院','Spring Boot 教程系列學(xué)習(xí)','http://www.roncoo.com/article/detail/124661');
insert into `learn_resource`(`id`,`author`,`title`,`url`) values (1001,'嘟嘟MD獨(dú)立博客','Spring Boot干貨系列','http://tengj.top/');
insert into `learn_resource`(`id`,`author`,`title`,`url`) values (1002,'后端編程嘟','Spring Boot視頻教程','http://www.toutiao.com/m1559096720023553/');
Controller層
到此為止,基本的配置結(jié)束了忘渔,我們開始實(shí)現(xiàn)業(yè)務(wù)的邏輯高帖,Controller層代碼如下
/** 教程頁面
* Created by tengj on 2017/12/19
*/
@Controller
@RequestMapping("/learn")
public class LearnController extends AbstractController{
@Autowired
private LearnService learnService;
private Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping("")
public String learn(Model model){
model.addAttribute("ctx", getContextPath()+"/");
return "learn-resource";
}
/**
* 查詢教程列表
* @param page
* @return
*/
@RequestMapping(value = "/queryLeanList",method = RequestMethod.POST)
@ResponseBody
public AjaxObject queryLearnList(Page<LeanQueryLeanListReq> page){
List<LearnResource> learnList=learnService.queryLearnResouceList(page);
PageInfo<LearnResource> pageInfo =new PageInfo<LearnResource>(learnList);
return AjaxObject.ok().put("page", pageInfo);
}
/**
* 新添教程
* @param learn
*/
@RequestMapping(value = "/add",method = RequestMethod.POST)
@ResponseBody
public AjaxObject addLearn(@RequestBody LearnResource learn){
learnService.save(learn);
return AjaxObject.ok();
}
/**
* 修改教程
* @param learn
*/
@RequestMapping(value = "/update",method = RequestMethod.POST)
@ResponseBody
public AjaxObject updateLearn(@RequestBody LearnResource learn){
learnService.updateNotNull(learn);
return AjaxObject.ok();
}
/**
* 刪除教程
* @param ids
*/
@RequestMapping(value="/delete",method = RequestMethod.POST)
@ResponseBody
public AjaxObject deleteLearn(@RequestBody Long[] ids){
learnService.deleteBatch(ids);
return AjaxObject.ok();
}
}
通用Service
正常情況下具體業(yè)務(wù)是每個(gè)模塊的service里面定義許多方法,然后mapper中實(shí)現(xiàn)畦粮。
但是博主查看插件文檔后發(fā)現(xiàn)一個(gè)通用Mapper在Spring4中的最佳用法散址。那就是通用的Service。
具體可以查看這里了解:https://gitee.com/free/Mapper2/blob/master/wiki/mapper/4.Spring4.md
定義通用service接口
/**
* 通用接口
*/
@Service
public interface IService<T> {
T selectByKey(Object key);
int save(T entity);
int delete(Object key);
int updateAll(T entity);
int updateNotNull(T entity);
List<T> selectByExample(Object example);
//TODO 其他...
}
具體實(shí)現(xiàn)通用接口類
/**
* 通用Service
* @param <T>
*/
public abstract class BaseService<T> implements IService<T> {
@Autowired
protected Mapper<T> mapper;
public Mapper<T> getMapper() {
return mapper;
}
@Override
public T selectByKey(Object key) {
//說明:根據(jù)主鍵字段進(jìn)行查詢宣赔,方法參數(shù)必須包含完整的主鍵屬性预麸,查詢條件使用等號
return mapper.selectByPrimaryKey(key);
}
@Override
public int save(T entity) {
//說明:保存一個(gè)實(shí)體,null的屬性也會保存儒将,不會使用數(shù)據(jù)庫默認(rèn)值
return mapper.insert(entity);
}
@Override
public int delete(Object key) {
//說明:根據(jù)主鍵字段進(jìn)行刪除吏祸,方法參數(shù)必須包含完整的主鍵屬性
return mapper.deleteByPrimaryKey(key);
}
@Override
public int updateAll(T entity) {
//說明:根據(jù)主鍵更新實(shí)體全部字段,null值會被更新
return mapper.updateByPrimaryKey(entity);
}
@Override
public int updateNotNull(T entity) {
//根據(jù)主鍵更新屬性不為null的值
return mapper.updateByPrimaryKeySelective(entity);
}
@Override
public List<T> selectByExample(Object example) {
//說明:根據(jù)Example條件進(jìn)行查詢
//重點(diǎn):這個(gè)查詢支持通過Example類指定查詢列钩蚊,通過selectProperties方法指定查詢列
return mapper.selectByExample(example);
}
}
到此基本的增刪改查通用service就寫好了贡翘,具體業(yè)務(wù)的service就直接繼承這個(gè)接口即可,也可以添加額外的方法,例如:
public interface LearnService extends IService<LearnResource>{
public List<LearnResource> queryLearnResouceList(Page<LeanQueryLeanListReq> page);
public void deleteBatch(Long[] ids);
}
具體實(shí)現(xiàn)service
/**
* Created by tengj on 2017/4/7.
*/
@Service
public class LearnServiceImpl extends BaseService<LearnResource> implements LearnService {
@Autowired
private LearnResourceMapper learnResourceMapper;
@Override
public void deleteBatch(Long[] ids) {
Arrays.stream(ids).forEach(id->learnResourceMapper.deleteByPrimaryKey(id));
}
@Override
public List<LearnResource> queryLearnResouceList(Page<LeanQueryLeanListReq> page) {
PageHelper.startPage(page.getPage(), page.getRows());
return learnResourceMapper.queryLearnResouceList(page.getCondition());
}
}
可以看到两疚,具體LearnServiceImpl這邊就實(shí)現(xiàn)了2個(gè)方法床估,其他的都使用了通用service的,在開發(fā)上剩下了許多功夫诱渤。
Mapper相關(guān)
在自動生成的mapper文件中實(shí)現(xiàn)sevice自定義的方法:
public interface LearnResourceMapper extends MyMapper<LearnResource> {
List<LearnResource> queryLearnResouceList(Map<String,Object> map);
}
LearnResourceMapper.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dudu.dao.LearnResourceMapper">
<resultMap id="BaseResultMap" type="com.dudu.domain.LearnResource">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="author" jdbcType="VARCHAR" property="author" />
<result column="title" jdbcType="VARCHAR" property="title" />
<result column="url" jdbcType="VARCHAR" property="url" />
</resultMap>
<select id="queryLearnResouceList" resultType="com.dudu.domain.LearnResource">
SELECT * from learn_resource where 1=1
<if test="author != null and author!= ''">
and author like CONCAT('%',#{author},'%')
</if>
<if test="title != null and title!= ''">
and title like CONCAT('%',#{title},'%')
</if>
order by id desc
</select>
</mapper>
IDEA可以安裝這個(gè)插件丐巫,這樣就可以直接從Mapper文件跳轉(zhuǎn)到xml了
最終項(xiàng)目效果如下,增刪改查分頁一個(gè)都不少:
上面提到druid有對應(yīng)的監(jiān)控界面,啟動項(xiàng)目后輸入http://localhost:8090/spring/druid 即可登錄,界面效果如下
總結(jié)
到此递胧,一套適合企業(yè)級開發(fā)的Spring Boot應(yīng)用模板就好了碑韵,Mybatis+通用Mapper、Mybatis Geneator確實(shí)可以省下很多開發(fā)成本缎脾,提高效率祝闻。前端整合了vue.js,具體看源碼。
想要查看更多Spring Boot干貨教程,可前往:Spring Boot干貨系列總綱
源碼下載
( ̄︶ ̄)↗[相關(guān)示例完整代碼]
- chapter11==》Spring Boot干貨系列:(十一)數(shù)據(jù)存儲篇-Spring Boot整合Mybatis通用Mapper插件
想要ace模板源碼的話遗菠,在博主公眾號回復(fù)關(guān)鍵字:ace
一直覺得自己寫的不是技術(shù)联喘,而是情懷,一篇篇文章是自己這一路走來的痕跡辙纬』碓猓靠專業(yè)技能的成功是最具可復(fù)制性的,希望我的這條路能讓你少走彎路贺拣,希望我能幫你抹去知識的蒙塵蓖谢,希望我能幫你理清知識的脈絡(luò),希望未來技術(shù)之巔上有你也有我譬涡。