利用闲余时间想自己搭建一个springboot+mybatis的项目,提升一下自己对项目的了解,在这里为自己创建项目的过程做一个记录,以便以后回忆。同时将搭建中遇到的问题也在这里做记录。
springboot的优势之一就是快速搭建项目,省去了自己导入jar包和配置xml的时间,使用非常方便。
开发前准备:创建数据库和测试表
CREATE DATABASE dev-demo;
CREATE TABLE t_user(
userId INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
userName VARCHAR(255) NOT NULL ,
password VARCHAR(255) NOT NULL ,
phone VARCHAR(255) NOT NULL,
birthDate date NOT NULL
) ENGINE=INNODB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8;
1、创建项目
1、打开IDEA,点击File→New→Project…,如图所示
2、当我们选择project…后,会看见如图所示的页面,选择Spring Initializr,点击NEXT即可。
3、接下来将看到如图所示的页面,修改项目名等信息然后点击NEXT进行下一步。
4、然后进行下一步。会看见如图所示的页面。 在当前页面中我们一次选择左侧的Web、SQL。然后在中间部分选择我们需要的选项,最终选择结果如最右侧所示。然后点击NEXT,进行下一步。
5、如图所示,进人创建项目的最后一个页面,在这里我们可以修改项目保存的位置。确认自己输入的内容,点击Fiish即可完成项目的创建
2、添加配置文件
1、finish之后项目结构如下图所示
resources文件夹下,static文件夹下存放静态文件,比如css、js、html和图片等 。
templates下存放html文件,controller默认访问该文件夹下的html文件。
这个在application.properties配置文件中是可以修改的。
2、配置application.yml(多环境,开发dev,测试test,生产prod)
更换application.properties文件为application.yml文件,这个文件更加简洁好用(备注:其实SpringBoot底层会把application.yml文件解析为application.properties), 文件结构如下:3依赖文件pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--JavaWeb开发启动器,包含了Web开发常用依赖包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--测试启动器,包含了测试常用依赖包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--数据库连接启动器,包含了连接库连接常用依赖包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mysql jdbc-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
</dependency>
<!--commons-lang3-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4、接下来尝试启动项目。发现项目可以正常启动了。可以打开浏览器访问http://localhost:8080/,访问结果如图所示。证明项目正常启动了。
3、项目整合druid连接池
1、在pom.xml文件中已添加druid依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
2、在yml文件中添加druid配置
spring:
datasource:
name: druidDataSource
#连接池类型
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
#你自己的数据库IP地址和数据库名,账号以及密码
url: jdbc:mysql://localhost:3306/dev_demo?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false
username: root
password: 123456
druid:
#连接池初始数量
initial-size: 5
#最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连接将被标记为不可用,然后被释放。设为0表示无限制。
min-idle: 5
#最大连接数
max-active: 20
#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
test-while-idle: true
#测试连接是否可用
validation-query: select 1
#获取连接等待超时时间,如果超过此时间将接到异常。
max-wait: 60000
4、项目整合mybatis-generator
1、在pom.xml文件中添加mybatis-generator、swagger、lombok依赖
<!--mybatis-generator代码生成器-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
<!-- swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
</dependency>
2、在resource文件夹下创建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="mysqlTables" targetRuntime="MyBatis3" defaultModelType="flat">
<!-- 生成的Java文件的编码 -->
<property name="javaFileEncoding" value="UTF-8"/>
<commentGenerator type="com.example.demo.MyCommentGenerator">
<property name="author" value="方鹏涛"/>
<property name="dateFormat" value="yyyy/MM/dd"/>
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/dev_demo"
userId="root"
password="123456">
<property name="useInformationSchema" value="true" />
</jdbcConnection>
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="com.example.demo.modules.user.entity" targetProject="F:\code\demo\src\main\java">
<!-- 是否对model添加 构造函数 -->
<property name="constructorBased" value="false"/>
<!-- 是否允许子包,即targetPackage.schemaName.tableName -->
<property name="enableSubPackages" value="false"/>
<!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
<property name="immutable" value="false"/>
<!-- 给Model添加一个父类
<property name="rootClass" value=""/>-->
<!-- 是否对类CHAR类型的列的数据进行trim操作 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置
如果maven工程只是单独的一个工程,targetProject="src/main/java"
若果maven工程是分模块的工程,targetProject="所属模块的名称",例如:
targetProject="ecps-manager-mapper",下同-->
<sqlMapGenerator targetPackage="com.example.demo.modules.user.mapper" targetProject="F:\code\demo\src\main\java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.example.demo.modules.user.mapper" targetProject="F:\code\demo\src\main\java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<property name="" value=""/>
</javaClientGenerator>
<!-- 指定数据库表 -->
<table schema="" tableName="t_user" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" selectByExampleQueryId="false">
</table>
</context>
</generatorConfiguration>
3、项目根目录下创建自定义中文注释配置文件MyCommentGenerator
package com.example.demo;
import org.mybatis.generator.api.FullyQualifiedTable;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
/**
* @ClassName MyCommentGenerator
* @Description mybatis-generator自定义代码生成注释类
* @Author 方鹏涛
* @Date 2021/5/28 16:16
* @Version 1.0
**/
public class MyCommentGenerator extends DefaultCommentGenerator {
private Properties properties;
public MyCommentGenerator() {
properties = new Properties();
}
/**
* 从该配置中的任何属性添加此实例的属性CommentGenerator配置。这个方法将在任何其他方法之前被调用。
* @param properties
*/
@Override
public void addConfigurationProperties(Properties properties) {
// 获取自定义的 properties
this.properties.putAll(properties);
}
/**
* 重写类注释
* @param topLevelClass
* @param introspectedTable
*/
@Override
public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
String author = properties.getProperty("author");
String dateFormat = properties.getProperty("dateFormat", "yyyy-MM-dd");
SimpleDateFormat dateFormatter = new SimpleDateFormat(dateFormat);
FullyQualifiedTable fullyQualifiedTable = introspectedTable.getFullyQualifiedTable();
Field field = new Field();
field.setVisibility(JavaVisibility.PRIVATE);
field.setType(new FullyQualifiedJavaType("long"));
field.setStatic(true);
field.setFinal(true);
field.setName("serialVersionUID");
field.setInitializationString("1L");
topLevelClass.addField(field);
FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType("Serializable");
FullyQualifiedJavaType imp = new FullyQualifiedJavaType("java.io.Serializable");
topLevelClass.addSuperInterface(fqjt);
topLevelClass.addImportedType(imp);
topLevelClass.addJavaDocLine("/**");
topLevelClass.addJavaDocLine(" * " + introspectedTable.getRemarks());
topLevelClass.addJavaDocLine(" * " + fullyQualifiedTable.getIntrospectedTableName());
topLevelClass.addJavaDocLine(" * @author " + author);
topLevelClass.addJavaDocLine(" * @date " + dateFormatter.format(new Date()));
topLevelClass.addJavaDocLine(" */");
//swagger包
topLevelClass.addImportedType("io.swagger.annotations.ApiModel");
topLevelClass.addImportedType("io.swagger.annotations.ApiModelProperty");
List<IntrospectedColumn> allColumns = introspectedTable.getAllColumns();
for (IntrospectedColumn column : allColumns) {
String shortName = column.getFullyQualifiedJavaType().getShortName();
if ("Date".equals(shortName)) {
topLevelClass.addImportedType("com.fasterxml.jackson.annotation.JsonFormat");
topLevelClass.addImportedType("org.springframework.format.annotation.DateTimeFormat");
}
}
//@Data包
topLevelClass.addImportedType("lombok.Data");
//@Data注解
topLevelClass.addAnnotation("@Data");
//swagger注解
topLevelClass.addAnnotation("@ApiModel(value = \"" + introspectedTable.getRemarks().split(";")[0] + "\")");
}
/**
* 重写字段注释
* @param field
* @param introspectedTable
* @param introspectedColumn
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
String remarks = introspectedColumn.getRemarks();
//根据参数和备注信息判断是否添加备注信息
if(StringUtility.stringHasValue(remarks)){
field.addJavaDocLine("/**");
StringBuilder sb = new StringBuilder();
sb.append(" * ");
//数据库中特殊字符需要转义
if(remarks.contains("\"")){
remarks = remarks.replace("\n", " ");
}
sb.append(remarks);
field.addJavaDocLine(sb.toString());
field.addJavaDocLine(" */");
}
//Date类型字段添加@JsonFormat、@DateTimeFormat注解
String shortName = field.getType().getShortName();
if ("Date".equals(shortName)) {
field.addAnnotation("@JsonFormat(pattern = \"yyyy.MM.dd\")");
field.addAnnotation("@DateTimeFormat(pattern = \"yyyy.MM.dd\")");
}
//属性添加swagger注解
field.addAnnotation("@ApiModelProperty(value=\"" + introspectedColumn.getRemarks() + "\")");
}
}
4、common包里创建MybatisGeneratorMain代码生成类
package com.example.demo.common;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName MybatisGeneratorMain
* @Description MybatisGenerator代码生成类
* @Author 方鹏涛
* @Date 2021/5/29 17:04
* @Version 1.0
**/
public class MybatisGeneratorMain {
public static void main(String[] args) throws Exception{
System.out.println("--------------------start generator-------------------");
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
InputStream inputStream = MybatisGeneratorMain.class.getClassLoader().getResourceAsStream("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(inputStream);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
System.out.println("--------------------end generator-------------------");
}
}
5、启动MybatisGeneratorMain 。通过控制台可以看见代码是否生成成功,或失败的原因。如果代码生成成功,可以在项目文件夹中看见生成的项目文件,这个过程共生成三个文件,一个实体类,dao,还有sql语句。
6、生成的bean如下。
package com.example.demo.modules.user.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 用户表
* t_user
* @author 方鹏涛
* @date 2021/05/29
*/
@ApiModel(value = "用户表")
@Data
public class TUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@ApiModelProperty(value="id")
private Integer userid;
/**
* 姓名
*/
@ApiModelProperty(value="姓名")
private String username;
/**
* 密码
*/
@ApiModelProperty(value="密码")
private String password;
/**
* 电话
*/
@ApiModelProperty(value="电话")
private String phone;
/**
* 生日
*/
@JsonFormat(pattern = "yyyy.MM.dd")
@DateTimeFormat(pattern = "yyyy.MM.dd")
@ApiModelProperty(value="生日")
private Date birthdate;
}
6、给生成的bean添加@TableName、@TableId注解。
5、Springboot整合Mybatis-Plus
1、在pom.xml文件中添加Mybatis-Plus依赖
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
2、在yml文件中添加Mybatis-Plus配置
# mybatis-plus配置
mybatis-plus:
# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
mapper-locations: classpath:mapper/*.xml
# 以下配置均有默认值,可以不设置
global-config:
db-config:
#主键类型 auto:"数据库ID自增" 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
id-type: auto
#字段策略 IGNORED:"忽略判断" NOT_NULL:"非 NULL 判断") NOT_EMPTY:"非空判断"
#ignored 不管有没有有设置属性,所有的字段都会设置到insert语句中,如果没设置值,全为null,这种在update 操作中会有风险,把有值的更新为null
#not_null 也是默认策略,也就是忽略null的字段,不忽略""
#not-empty 为null,为空串的忽略,就是如果设置值为null,“”,不会插入数据库
field-strategy: NOT_EMPTY
#数据库类型
db-type: MYSQL
configuration:
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
call-setters-on-nulls: true
#是否开启mybatis二级缓存,默认为true
cache-enabled: false
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3、根目录下新增MybatisPlusConfig配置类,开启MybatisPlus分页功能
package com.example.demo;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @ClassName MybatisPlusConfig
* @Description MybatisPlus配置类,开启mybatis-plus物理分页功能
* @Author 方鹏涛
* @Date 2021/5/31 9:57
* @Version 1.0
**/
@Configuration
@MapperScan("com.example.demo.modules.*.mapper*") //指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类,可代替@Mapper注解
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor page = new PaginationInterceptor();
return page;
}
}
4、Mapper继承MybatisPlus的BaseMapper
package com.example.demo.modules.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.modules.user.entity.TUser;
/**
* 用户管理dao层接口
* @author 方鹏涛
* @date 2021/05/29
*/
public interface TUserMapper extends BaseMapper<TUser> {
}
5、Service继承MybatisPlus的IService
package com.example.demo.modules.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.modules.user.entity.TUser;
public interface TUserService extends IService<TUser> {
}
5、业务实现类继承MybatisPlus的ServiceImpl,实现业务接口
package com.example.demo.modules.user.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.modules.user.entity.TUser;
import com.example.demo.modules.user.mapper.TUserMapper;
import com.example.demo.modules.user.service.TUserService;
import org.springframework.stereotype.Service;
/**
* @ClassName TUserServiceImpl
* @Description TODO
* @Author Administrator
* @Date 2021/5/31 10:40
* @Version 1.0
**/
@Service
public class TUserServiceImpl extends ServiceImpl<TUserMapper, TUser> implements TUserService {
}
6、Controller继承MybatisPlus的ApiController
package com.example.demo.modules.user.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.modules.user.entity.TUser;
import com.example.demo.modules.user.service.TUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ClassName TUserController
* @Description 用户管理控制类
* @Author 方鹏涛
* @Date 2021/5/31 10:43
* @Version 1.0
**/
@RestController
@RequestMapping("/user")
public class TUserController extends ApiController {
@Autowired
private TUserService userService;
@GetMapping("queryUserPageList")
public R queryUserPageList(Page<TUser> page,TUser user){
QueryWrapper<TUser> queryWrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(user.getUsername())){
queryWrapper.like("userName",user.getUsername());
}
IPage<TUser> userPageList = userService.page(page,queryWrapper);
return success(userPageList);
}
}