是一个
的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。特点:
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
步骤1: 添加mybatis-plus的starter依赖
<!--mybatis-plus启动器依赖
无需再添加mybatis-starter
-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
步骤2:使用MyBatis-plus的Generator
生成:实体类,controller,service,ServiceImpl,Mapper
a.添加生成器依赖
<!--mybatisPlus 自动生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
<!--mybatisPlus默认模板-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
b.创建生成代码工具类
MybatisPlusCodeUtils.java,运行后将帮助我们自动生成代码
package com.woniu.util;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
/**
* MyBatisPlusCode代码生成工具类
*/
public class MyBatisPlusCodeUtil {
private static final String XML_PATH="/resources/mapper/";
private static final String ENTITY_IGNORE_PREFIX="smbms_";
/**
* 启动方法
* @param args
*/
public static void main(String[] args) {
try {
generator("gp",//作者
"jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai",
"com.mysql.cj.jdbc.Driver",//数据库驱动
"root",//数据库帐号
"root",//数据库密码
"com.woniu",//项目最大的包名
"springboot-demo03",//项目名或项目模块名
"smbms_user,smbms_role");//要操作的表名,多个表名用逗号隔开
System.out.println("mybaits代码生成成功");
}catch (Exception e){
e.printStackTrace();
}
}
/**
* Mybatis一键生成entity,mapper,mapper.xml,service,serviceImpl,controller
* @param author 开发人员
* @param url 驱动连接的URL
* @param driverName 驱动名称
* @param username 数据库连接用户名
* @param password 数据库连接密码
* @param parentPackage 父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名
* @param projectModule 项目名
* @param tableName 表名,多个表名逗号隔开
*/
public static void generator(String author,
String url,
String driverName,
String username,
String password,
String parentPackage,
String projectModule,
String tableName) {
AutoGenerator mpg = new AutoGenerator();
mpg.setGlobalConfig(globalConfig(author,projectModule));//全局配置
mpg.setDataSource(dataSourceConfig(url,driverName,username,password));//数据源配置
mpg.setPackageInfo(packageConfig(parentPackage));//包配置
mpg.setStrategy(strategyConfig(tableName));//策略配置
mpg.setTemplate(templateConfig());//模板配置
mpg.execute();
}
/**
* 全局配置
* @param author 开发人员
* @param projectModule 项目模块名
* @return GlobalConfig
*/
private static GlobalConfig globalConfig (String author, String projectModule) {
String projectPath = System.getProperty("user.dir");
GlobalConfig globalConfig = new GlobalConfig();
// 文件输出目录
//如果要在项目中生成用这个
// globalConfig.setOutputDir(projectPath + "\\src\\main\\java");
//如果要在模块中生成用这个
globalConfig.setOutputDir(projectPath + "\\" + projectModule + "\\src\\main\\java");
// 添加作者信息
globalConfig.setAuthor(author);
//设置时间类型为Date Java8新出的LocalDatetime -->并不是java.util.Date
globalConfig.setDateType(DateType.TIME_PACK);
// 生成文件后不默认打开
globalConfig.setOpen(false);
// 自定义service生成的名字,用于删除自动生成的I前缀
globalConfig.setServiceName("%sService");
// 自定义dao生成的名字,如果不指定默认为%sMapper
//globalConfig.setMapperName("%sDao");
return globalConfig;
}
/**
* 数据源设置
* @param url 驱动连接的URL
* @param driverName 驱动名称
* @param username 数据库连接用户名
* @param password 数据库连接密码
* @return DataSourceConfig
*/
private static DataSourceConfig dataSourceConfig (String url,
String driverName,
String username,
String password) {
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl(url);
dataSourceConfig.setDriverName(driverName);
dataSourceConfig.setUsername(username);
dataSourceConfig.setPassword(password);
return dataSourceConfig;
}
/**
* 包配置
* @param parentPackage 父包名,最大的包名
* @return PackageConfig
*/
private static PackageConfig packageConfig(String parentPackage) {
// 包配置
PackageConfig packageConfig = new PackageConfig();
// 包名
packageConfig.setParent(parentPackage);
//各个包目录起名
packageConfig.setEntity("entity");
packageConfig.setMapper("mapper");
packageConfig.setXml("mapper");
packageConfig.setService("service");
return packageConfig;
}
/**
* 策略配置
* @param tableName 数据库表名称,多个用英文逗号隔开
* @return StrategyConfig
*/
private static StrategyConfig strategyConfig (String tableName) {
// 策略配置
StrategyConfig strategyConfig = new StrategyConfig();
// 表名驼峰命名
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
// 字段驼峰命名
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
// 设置去除表前缀
strategyConfig.setTablePrefix(ENTITY_IGNORE_PREFIX);
// 设置实体类的lombok(此处看个人使用,如果不使用lombok,那么在生成之后再去添加构造方法等等)
strategyConfig.setEntityLombokModel(true);
//strategyConfig.setRestControllerStyle(true);
// scanner("表名,多个英文逗号分割").split(",")
strategyConfig.setInclude((tableName).split(","));
// 驼峰生成方法
strategyConfig.setControllerMappingHyphenStyle(true);
return strategyConfig;
}
/**
* 模板配置项
* @return TemplateConfig
*/
private static TemplateConfig templateConfig () {
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(ConstVal.TEMPLATE_XML);
//不生成mapper.xml文件
templateConfig.setXml(null);
//不生成service
//templateConfig.setService(null);
//不生成service实现类
//templateConfig.setServiceImpl(null);
//不生成controller类
templateConfig.setController(null);
return templateConfig;
}
}
c.使用MyBatisPlus-CRUD
查询列表
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/list")
public List<User> getUserList(){
//QueryWrapp 包装器,用于封装查询条件 ,如果为null则表示不限条件
List<User> userList = userService.list(null);
return userList;
}
}
根据Id查询
@GetMapping("/getById/{id}")
public User getUserById(@PathVariable("id") Integer id){
//QueryWrapp 包装器,用于封装查询条件 ,如果为null则表示不限条件
User user = userService.getById(id);
return user;
}
分页查询
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
首先,添加分页拦截器配置
@Configuration
public class MyBatisPlusConfig {
//配置分页插件
/**
* 防止 修改与删除时对全表进行操作
*
* @return
*/
@Bean
public BlockAttackInnerInterceptor blockAttackInnerInterceptor() {
return new BlockAttackInnerInterceptor();
}
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
/**
* ConfigurationCustomizer,这里引用的是MyBatisPlus自定义的一个和MyBatis同名的接口,com.baomidou.mybatisplus.spring.boot.starter.ConfigurationCustomizer,
* 因此必须使用MyBatisPlus的ConfigurationCustomizer才行
*
* @return
*/
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return new ConfigurationCustomizer() {
@Override
public void customize(MybatisConfiguration configuration) {
configuration.setCacheEnabled(true);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCallSettersOnNulls(true);
configuration.setJdbcTypeForNull(JdbcType.NULL);
}
};
}
}
执行分页查询
@GetMapping("/list")
public Page<User> getUserList(){
Page<User> page = new Page<>(1,5);
//注意:传入的page与对象与返回的page对象是同一个
Page<User> pageInfo = userService.page(page,null);
return pageInfo;
}
按条件查询的分页:
UserController:
@GetMapping("/list")
public Page<User> getUserList(@RequestParam(name="pageNum",defaultValue = "1") Integer pageNum, @RequestParam(name="pageSize",defaultValue = "5") Integer pageSize,
User user){
Page<User> page = userService.getPage(pageNum,pageSize,user);
return page;
}
UserServiceImpl业务实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private UserMapper userMapper;
/**
* 执行分页带条件查询
* @param pageNum
* @param pageSize
* @param user
* @return
*/
public Page<User> getPage(Integer pageNum, Integer pageSize, User user) {
//创建分页对象
Page<User> page = new Page<>(pageNum,pageSize);
//QueryWrapp查询包装器
QueryWrapper<User> wrapper = new QueryWrapper<>();
if(user.getUserCode()!=null && !user.getUserCode().equals("")) {
wrapper.like("userCode", user.getUserCode()); //默认为and关系
}
if(user.getGender()!=null) {
wrapper.eq("gender", user.getGender());
}
// wrapper.or().eq("gender",user.getGender());
wrapper.orderByAsc("id"); //查询中的排序列
page = userMapper.selectPage(page,wrapper);
return page;
}
}
2.SpringBoot实战-2
2-1 消息转换器配置
SpringMVC中xml与配置类实现消息转换器配置
HttpMessageConverter接口
|-StringHttpMessageConverter 实现类 [字符串消息转换器]
@ResponseBody
Pojo对象--> JSON格式 -->消息转换器 [Jackson,Fastjson]
如果使用fastjson 需要单独添加依赖,SpringBoot默认使用Jackson消息转换,不需要添加依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
在WebMvcConfig配置类中添加消息转换器
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
/**
* 配置SpringBoot消息转换器
* @param converters
*/
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
List<HttpMessageConverter<?>> result = new ArrayList<>(converters.size());
//配置Jackson消息转换器
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter();
//设置转换器配置信息
MediaType mediaType = MediaType.valueOf("application/json;charset=UTF-8");
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(mediaType);
converter.setSupportedMediaTypes(mediaTypeList);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd E"));
converter.setObjectMapper(objectMapper);
result.add(converter);
//配置fasterJSON消息转换
//使用FastJson作为HTTP的序列化和反序列工具
// 1.定义Converter转换器对象
// FastJsonHttpMessageConverter converter2 =
// new FastJsonHttpMessageConverter();
// // 2.1设置转换器的配置信息
// FastJsonConfig config = new FastJsonConfig();
// config.setSerializerFeatures(
// //List字段如果为null,输出为[],而非null
// SerializerFeature.WriteNullListAsEmpty,
// //字符类型字段如果为null,输出为"",而非null
// // SerializerFeature.WriteNullStringAsEmpty,
// //Boolean字段如果为null,输出为falseJ,而非null
// SerializerFeature.WriteNullBooleanAsFalse,
// //消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)
// SerializerFeature.DisableCircularReferenceDetect,
// //是否输出值为null的字段,默认为false。
// SerializerFeature.WriteMapNullValue,
// SerializerFeature.WriteDateUseDateFormat
// );
// // 2.2设置编码,处理中文乱码
// converter2.setDefaultCharset(Charset.forName("UTF-8"));
// config.setCharset(Charset.forName("UTF-8"));
// // 3.将设置添加到转换器中
// converter2.setFastJsonConfig(config);
// result.add(converter2);
//配置编码转换
result.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
//清除转换器,添加
converters.clear();
//添加转换器列表
converters.addAll(result);
}
}
针对日期 Date类型实体类字段
/**
* 出生日期
*/
@JsonFormat(pattern="yyyy-MM-dd") //Jackson 将Date日期类型转换为Json串时
@JSONField(format = "yyyy-MM-dd") //fastjson 将Date日期类型转换为Json串时
private Date birthday;
2-2 类型转换器
User里面的birthday属性是一个Date对象类型,提交的日期是一个字符串类型,这个时候就需要进行类型转换
第一种方式就是在user类的属性上添加注解 @DateTimeFormat(pattern = "yyyy-mm-dd")
第二种方式就是我们自己要自定义一个类型转换器
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
// 注册类型 转换器
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, Date>() {
@Override
public Date convert(String source) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(source);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
});
}
}
如果将String转LocaleDate或LocaleDateTime
registry.addConverter(new Converter<String, LocalDateTime>(){
@Override
public LocalDateTime convert(String source) {
System.out.println("String转LocalDateTime.............");
if(source.trim().length() ==0 ){
return null;
}
try {
//先尝试先尝试
// 格式ISO : 2019-07-15T16:00:00
return LocalDateTime.parse(source);
} catch (Exception e) {
// e.printStackTrace();
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
}
});
//添加String转换LocalDate格式
registry.addConverter(new Converter<String, LocalDate>(){
@Override
public LocalDate convert(String source) {
System.out.println("String转LocalDate.............");
if(source.trim().length() ==0 ){
return null;
}
try {
//先尝试先尝试
return LocalDate.parse(source);
} catch (Exception e) {
// e.printStackTrace();
return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
}
});
2-3 文件上传
编写上传文件表单
<form action="toadd" method="post" enctype="multipart/form-data">
<p>用户名:<input type="text" name="userCode" /></p>
<p>密码:<input type="text" name="userPassword" /></p>
<p>日期:<input type="datetime-local" name="birthday" /></p>
<p>文件1:<input type="file" name="uploadfile" /></p>
<p>文件2:<input type="file" name="uploadfile" /></p>
<p> <input type="submit" value="提交" /></p>
</form>
处理上传文件请求:
@PostMapping("/toadd")
public String toAdd(User user, @RequestParam("uploadfile") List<MultipartFile> files,
HttpServletRequest request) throws FileNotFoundException {
System.out.println(user);
//上传文件的路径
String uploadPath = ResourceUtils.getURL("classpath:").getPath()+"static/pic/";
System.out.println(uploadPath);
//如果上传文件目录不存在,则创建
File uploadDir = new File(uploadPath);
if(!uploadDir.exists()){
uploadDir.mkdirs();
}
//执行批量上传
for(int i=0;i<files.size();i++){
MultipartFile file = files.get(i);
if (file.isEmpty()) {
return "上传第" + (i+1) + "个文件失败";
}
//重命名文件名,随机
String originalFilename = file.getOriginalFilename();
String ext = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = UUID.randomUUID().toString().replace("-","")+ext;
//生成目标File对象
File targetFile = new File(uploadPath+newFileName);
try {
//拷贝文件
file.transferTo(targetFile);
} catch (IOException exception) {
exception.printStackTrace();
return "上传第" + (i+1) + "个文件失败";
}
}
// user.setIdpicpath("pic/"+newFileName);
//写入user 到数据库
return "上传文件OK!";
}