一、前言 如果项目中使用到了MyBatis框架,那么使用通用Mapper和PageHelper分页插件将极大的简化我们的操作。通用Mapper可以简化对单表的CRUD操作,PageHelper分页插件可以帮我们自动拼接分页SQL,并且可以使用MyBatis Geneator来自动生成实体类,Mapper接口和Mapper xml代码,非常的方便。插件地址及作者链接https://gitee.com/free。
二、引入依赖 这里使用Spring Boot来构建,可参考 《Spring Boot整合MyBatis》 搭建一个Spring boot + MyBatis的框架,然后在pom中引入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency> <!-- mysql 驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.22</version> </dependency> <!--通用mapper--> <!-- 通用Mapper插件文档地址:https://gitee.com/free/Mapper/wikis/Home --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.1.5</version> </dependency> <!--pagehelper 分页插件--> <!-- 分页插件文档地址:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.13</version> </dependency>
接着在pom中配置MyBatis Geneator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.7</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.21</version> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>4.1.5</version> </dependency> </dependencies> <configuration> <!-- 对应generator配置文件的路径 --> <configurationFile>src/main/resources/mybatis-generator.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> </plugin>
三、配置Geneator 3.1 mybatis-generator.xml 在路径src/main/resources/下新建mybatis-generator.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 <?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> <!-- 本地数据库驱动程序jar包的全路径 <classPathEntry location="E:\repo\mysql\mysql-connector-java\8.0.21\mysql-connector-java-8.0.21.jar"/> --> <!-- 一个数据库一个context --> <!--defaultModelType="flat" 大数据字段,不分表 --> <context id="mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat"> <!-- 自动识别数据库关键字,默认false,如果设置为true,根据SqlReservedWords中定义的关键字列表; 一般保留默认值,遇到数据库关键字(Java关键字),使用columnOverride覆盖 --> <property name="autoDelimitKeywords" value="true" /> <!-- 生成的Java文件的编码 --> <property name="javaFileEncoding" value="utf-8" /> <!-- beginningDelimiter和endingDelimiter:指明数据库的用于标记数据库对象名的符号,比如ORACLE就是双引号,MYSQL默认是`反引号; --> <property name="beginningDelimiter" value="`" /> <property name="endingDelimiter" value="`" /> <!-- 格式化java代码 --> <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/> <!-- 格式化XML代码 --> <property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/> <plugin type="org.mybatis.generator.plugins.SerializablePlugin" /> <plugin type="org.mybatis.generator.plugins.ToStringPlugin" /> <plugin type="tk.mybatis.mapper.generator.MapperPlugin"> <property name="mappers" value="com.wno704.boot.config.BaseMapper" /> <!--caseSensitive默认false,当数据库表名区分大小写时,可以将该属性设置为true--> <property name="caseSensitive" value="false"/> </plugin> <!-- 阻止生成自动注释 --> <commentGenerator> <property name="javaFileEncoding" value="UTF-8"/> <!-- 是否生成注释代时间戳--> <property name="suppressDate" value="true"/> <!-- 是否取消注释 --> <property name="suppressAllComments" value="true"/> </commentGenerator> <!--数据库链接地址账号密码--> <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&allowMultiQueries=true&useSSL=false" userId="spring" password="spring#123"> <!--MySQL 8.x 需要指定服务器的时区--> <property name="serverTimezone" value="UTC"/> <!--MySQL 不支持 schema 或者 catalog 所以需要添加这个--> <!--参考 : http://www.mybatis.org/generator/usage/mysql.html--> <property name="nullCatalogMeansCurrent" value="true"/> <!-- MySQL8默认启用 SSL ,不关闭会有警告--> <property name="useSSL" value="false"/> </jdbcConnection> <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制--> <javaTypeResolver> <!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) --> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!--生成Model类存放位置--> <javaModelGenerator targetPackage="com.wno704.boot.model" targetProject="src/main/java"> <!-- 是否对model添加 构造函数 --> <property name="constructorBased" value="false"/> <!-- 是否允许子包,即targetPackage.schemaName.tableName --> <property name="enableSubPackages" value="true"/> <!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 --> <property name="immutable" value="false"/> <!-- 给Model添加一个父类 --> <!--<property name="rootClass" value="com.foo.louis.Hello"/>--> <!-- 是否对类CHAR类型的列的数据进行trim操作 --> <property name="trimStrings" value="true"/> </javaModelGenerator> <!--生成映射文件存放位置--> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!--生成Dao类存放位置--> <!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码 type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象 type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.wno704.boot.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="false"/> <!--定义Maper.java 源代码中的ByExample() 方法的可视性,可选的值有: public;private;protected;default,注意:如果 targetRuntime="MyBatis3",此参数被忽略 --> <property name="exampleMethodVisibility" value=""/> <!--方法名计数器Important note: this property is ignored if the target runtime is MyBatis3.--> <property name="methodNameCalculator" value=""/> <!--为生成的接口添加父接口--> <property name="rootInterface" value=""/> </javaClientGenerator> <!--生成对应表及类名去掉Mybatis Generator生成的一堆 example--> <table tableName="t_user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"> <generatedKey column="USER_ID" sqlStatement="mysql" identity="true"/> </table> <!-- <table tableName="t_dept" domainObjectName="Dept" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"> <generatedKey column="DEPT_ID" sqlStatement="mysql" identity="true"/> </table> --> <!-- <table tableName="person" domainObjectName="Person" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"> <generatedKey column="id" sqlStatement="mysql" identity="true"/> </table> --> </context> </generatorConfiguration>
更详细的说明可参考链接: http://blog.csdn.net/isea533/article/details/42102297 。 代码生成
3.2 BaseMapper 1 2 3 4 public interface BaseMapper<T> extends Mapper<T>, MySqlMapper<T> { } 值得注意的是,该接口不能被扫描到,应该和自己定义的Mapper分开。自己定义的Mapper都需要继承这个接口。
3.3 mybatis-generator:generate 配置好MyBatis Geneator后,在eclipse中运行命令mybatis-generator:generate: 如下图所示: 生成的代码如下:
以下为自动成成的代码:
3.3.1 User 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 @Table(name = "t_user") public class User implements Serializable { /** * 用户ID */ @Id @Column(name = "USER_ID") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userId; /** * 用户名 */ @Column(name = "USERNAME") private String username; /** * 密码 */ @Column(name = "PASSWORD") private String password; /** * 部门ID */ @Column(name = "DEPT_ID") private Long deptId; /** * 邮箱 */ @Column(name = "EMAIL") private String email; /** * 联系电话 */ @Column(name = "MOBILE") private String mobile; /** * 状态 0锁定 1有效 */ @Column(name = "STATUS") private String status; /** * 创建时间 */ @Column(name = "CREATE_TIME") private Date createTime; /** * 修改时间 */ @Column(name = "MODIFY_TIME") private Date modifyTime; /** * 最近访问时间 */ @Column(name = "LAST_LOGIN_TIME") private Date lastLoginTime; /** * 性别 0男 1女 2保密 */ @Column(name = "SSEX") private String ssex; /** * 是否开启tab,0关闭 1开启 */ @Column(name = "IS_TAB") private String isTab; /** * 主题 */ @Column(name = "THEME") private String theme; /** * 头像 */ @Column(name = "AVATAR") private String avatar; /** * 描述 */ @Column(name = "DESCRIPTION") private String description; private static final long serialVersionUID = 1L; /** * 获取用户ID * * @return USER_ID - 用户ID */ public Long getUserId() { return userId; } /** * 设置用户ID * * @param userId 用户ID */ public void setUserId(Long userId) { this.userId = userId; } /** * 获取用户名 * * @return USERNAME - 用户名 */ public String getUsername() { return username; } /** * 设置用户名 * * @param username 用户名 */ public void setUsername(String username) { this.username = username == null ? null : username.trim(); } /** * 获取密码 * * @return PASSWORD - 密码 */ public String getPassword() { return password; } /** * 设置密码 * * @param password 密码 */ public void setPassword(String password) { this.password = password == null ? null : password.trim(); } /** * 获取部门ID * * @return DEPT_ID - 部门ID */ public Long getDeptId() { return deptId; } /** * 设置部门ID * * @param deptId 部门ID */ public void setDeptId(Long deptId) { this.deptId = deptId; } /** * 获取邮箱 * * @return EMAIL - 邮箱 */ public String getEmail() { return email; } /** * 设置邮箱 * * @param email 邮箱 */ public void setEmail(String email) { this.email = email == null ? null : email.trim(); } /** * 获取联系电话 * * @return MOBILE - 联系电话 */ public String getMobile() { return mobile; } /** * 设置联系电话 * * @param mobile 联系电话 */ public void setMobile(String mobile) { this.mobile = mobile == null ? null : mobile.trim(); } /** * 获取状态 0锁定 1有效 * * @return STATUS - 状态 0锁定 1有效 */ public String getStatus() { return status; } /** * 设置状态 0锁定 1有效 * * @param status 状态 0锁定 1有效 */ public void setStatus(String status) { this.status = status == null ? null : status.trim(); } /** * 获取创建时间 * * @return CREATE_TIME - 创建时间 */ public Date getCreateTime() { return createTime; } /** * 设置创建时间 * * @param createTime 创建时间 */ public void setCreateTime(Date createTime) { this.createTime = createTime; } /** * 获取修改时间 * * @return MODIFY_TIME - 修改时间 */ public Date getModifyTime() { return modifyTime; } /** * 设置修改时间 * * @param modifyTime 修改时间 */ public void setModifyTime(Date modifyTime) { this.modifyTime = modifyTime; } /** * 获取最近访问时间 * * @return LAST_LOGIN_TIME - 最近访问时间 */ public Date getLastLoginTime() { return lastLoginTime; } /** * 设置最近访问时间 * * @param lastLoginTime 最近访问时间 */ public void setLastLoginTime(Date lastLoginTime) { this.lastLoginTime = lastLoginTime; } /** * 获取性别 0男 1女 2保密 * * @return SSEX - 性别 0男 1女 2保密 */ public String getSsex() { return ssex; } /** * 设置性别 0男 1女 2保密 * * @param ssex 性别 0男 1女 2保密 */ public void setSsex(String ssex) { this.ssex = ssex == null ? null : ssex.trim(); } /** * 获取是否开启tab,0关闭 1开启 * * @return IS_TAB - 是否开启tab,0关闭 1开启 */ public String getIsTab() { return isTab; } /** * 设置是否开启tab,0关闭 1开启 * * @param isTab 是否开启tab,0关闭 1开启 */ public void setIsTab(String isTab) { this.isTab = isTab == null ? null : isTab.trim(); } /** * 获取主题 * * @return THEME - 主题 */ public String getTheme() { return theme; } /** * 设置主题 * * @param theme 主题 */ public void setTheme(String theme) { this.theme = theme == null ? null : theme.trim(); } /** * 获取头像 * * @return AVATAR - 头像 */ public String getAvatar() { return avatar; } /** * 设置头像 * * @param avatar 头像 */ public void setAvatar(String avatar) { this.avatar = avatar == null ? null : avatar.trim(); } /** * 获取描述 * * @return DESCRIPTION - 描述 */ public String getDescription() { return description; } /** * 设置描述 * * @param description 描述 */ public void setDescription(String description) { this.description = description == null ? null : description.trim(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); sb.append(" ["); sb.append("Hash = ").append(hashCode()); sb.append(", userId=").append(userId); sb.append(", username=").append(username); sb.append(", password=").append(password); sb.append(", deptId=").append(deptId); sb.append(", email=").append(email); sb.append(", mobile=").append(mobile); sb.append(", status=").append(status); sb.append(", createTime=").append(createTime); sb.append(", modifyTime=").append(modifyTime); sb.append(", lastLoginTime=").append(lastLoginTime); sb.append(", ssex=").append(ssex); sb.append(", isTab=").append(isTab); sb.append(", theme=").append(theme); sb.append(", avatar=").append(avatar); sb.append(", description=").append(description); sb.append(", serialVersionUID=").append(serialVersionUID); sb.append("]"); return sb.toString(); } }
3.3.2 UserMapper 1 2 public interface UserMapper extends BaseMapper<User> { }
3.3.3 UserMapper.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?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.wno704.boot.mapper.UserMapper"> <resultMap id="BaseResultMap" type="com.wno704.boot.model.User"> <!-- WARNING - @mbg.generated --> <id column="USER_ID" jdbcType="BIGINT" property="userId" /> <result column="USERNAME" jdbcType="VARCHAR" property="username" /> <result column="PASSWORD" jdbcType="VARCHAR" property="password" /> <result column="DEPT_ID" jdbcType="BIGINT" property="deptId" /> <result column="EMAIL" jdbcType="VARCHAR" property="email" /> <result column="MOBILE" jdbcType="VARCHAR" property="mobile" /> <result column="STATUS" jdbcType="CHAR" property="status" /> <result column="CREATE_TIME" jdbcType="TIMESTAMP" property="createTime" /> <result column="MODIFY_TIME" jdbcType="TIMESTAMP" property="modifyTime" /> <result column="LAST_LOGIN_TIME" jdbcType="TIMESTAMP" property="lastLoginTime" /> <result column="SSEX" jdbcType="CHAR" property="ssex" /> <result column="IS_TAB" jdbcType="CHAR" property="isTab" /> <result column="THEME" jdbcType="VARCHAR" property="theme" /> <result column="AVATAR" jdbcType="VARCHAR" property="avatar" /> <result column="DESCRIPTION" jdbcType="VARCHAR" property="description" /> </resultMap> </mapper>
3.4 扫描mapper 3.4.1 需要启动类上增加mapper扫描 @MapperScan("com.wno704.boot.mapper")
注意
:引用路径为:import tk.mybatis.spring.annotation.MapperScan;
3.4.2 application.yml配置mybatis 1 2 3 4 5 6 7 mybatis: # type-aliases扫描路径 # type-aliases-package: # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE
四、测试 4.1 通用Service BaseService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface BaseService<T> { List<T> selectAll(); int save(T entity); int delete(Object key); int updateAll(T entity); int updateNotNull(T entity); List<T> selectByExample(Object example); }
4.2 BaseService实现类 BaseServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public abstract class BaseServiceImpl<T> implements BaseService<T> { @Autowired protected Mapper<T> mapper; public Mapper<T> getMapper() { return mapper; } @Override public List<T> selectAll() { //说明:查询所有数据 return this.mapper.selectAll(); } @Override public int save(T entity) { //说明:保存一个实体,null的属性也会保存,不会使用数据库默认值 return this.mapper.insert(entity); } @Override public int delete(Object key) { //说明:根据主键字段进行删除,方法参数必须包含完整的主键属性 return this.mapper.deleteByPrimaryKey(key); } @Override public int updateAll(T entity) { //说明:根据主键更新实体全部字段,null值会被更新 return this.mapper.updateByPrimaryKey(entity); } @Override public int updateNotNull(T entity) { //根据主键更新属性不为null的值 return this.mapper.updateByPrimaryKeySelective(entity); } @Override public List<T> selectByExample(Object example) { //说明:根据Example条件进行查询 //重点:这个查询支持通过Example类指定查询列,通过selectProperties方法指定查询列 return this.mapper.selectByExample(example); } }
4.3 定义UserService 1 2 public interface UserService extends BaseService<User>{ }
4.4 UserService实现类 UserServiceImpl.java
1 2 3 @Repository("userService") public class UserServiceImpl extends BaseServiceImpl<User> implements UserService{ }
4.5 创建测试Controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @RestController public class TestController { @Autowired private PersonService personService; @Autowired private UserService userService; @RequestMapping( value = "/queryperson", method = RequestMethod.GET) public String queryStudentBySno() { return this.personService.selectAll().toString(); } @RequestMapping( value = "/queryuser", method = RequestMethod.GET) public String queryUser() { return this.userService.selectAll().toString(); } @RequestMapping( value = "/queryuserpage", method = RequestMethod.GET) public String queryUserPage() { PageHelper.startPage(2, 2); List<User> list = this.userService.selectAll(); PageInfo<User> pageInfo = new PageInfo<User>(list); List<User> result = pageInfo.getList(); for (User u : result) { System.out.println(u.getUsername()); } return pageInfo.getList().toString(); } }
访问路径 http://localhost:8080/queryuserpage