如果遗漏了哪些东西,告诉我一声,哈哈。欢迎加群一起学习:43827511
IntelliJ IDEA 首先创建一个项目,创建时选择Spring Initializr,然后Next,如下图:
填写项目信息,如下图:
填写项目使用到技术,上面的Spring Boot版本建议选择最新的稳定版,下面勾选上Web就可以了,如下图:
最后一步,填写工程名字点击Finish:
第一次创建时系统会去下载需要的依赖等,耗时稍长
Spring Boot通常有一个名为*Application的入口类,入口类里有一个main方法,这个main方法其实就是一个标准的Java应用的入口方法。在main方法中使用SpringApplication.run(PlamanagerApplication.class, args),启动Spring Boot应用项目。
@SpringBootApplication是Spring Boot的核心注解它是一个组合注解:
@SpringBootApplication注解主要组合了
@Configuration
@EnableAutoConfiguration(让Spring Boot根据类路径中的jar包依赖为当前项目进行自动配置)
例如,添加了spring-boot-starter-web依赖,会自动添加Tomcat和SpringMVC的依赖,那么Spring Boot会对Tomcat和SpringMVC进行自动配置。
又如,添加了spring-boot-starter-data-jpa依赖,Spring Boot会自动进行JPA相关的配置。
Spring Boot会自动扫描@SpringBootApplication所在类的同级包以及下级包里的Bean。建议入口类放置的位置在groupId+arctifactID组合的包名下。
@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中
spring-boot-devtools是一个为开发者服务的一个模块,其中最重要的功能就是自动应用代码更改到最新的App上面去。
原理是在发现代码有更改之后,重新启动应用,但是速度比手动停止后再启动更快。
其深层原理是使用了两个ClassLoader,一个Classloader加载那些不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为restart ClassLoader
,这样在有代码更改的时候,原来的restart ClassLoader被丢弃,重新创建一个restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间。
即devtools会监听classpath下的文件变动,并且会立即重启应用(发生在保存时机)
开启idea自动make功能
1.CTRL + SHIFT + A --> 查找 make project automatically --> 选中
2.CTRL + SHIFT + A --> 查找Registry --> 找到并勾选 compiler.automake.allow.when.app.running
org.springframework.boot
spring-boot-devtools
true
org.springframework.boot
spring-boot-maven-plugin
true
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.1.RELEASE
com.boot
plamanager
0.0.1-SNAPSHOT
plamanager
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-devtools
true
org.springframework.boot
spring-boot-maven-plugin
true
JPA中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
Spring Data JPA是Spring Data的一个子项目,它通过提供基于JPA的Repository极大地减少了JPA作为数据访问方案的代码量。
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
runtime
springboot创建时默认给了一个application.properties配置文件,这个properties格式的文件,好像要多写好多代码,所以改用yml后缀的文件
application.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/hello?useUnicode=true&characterEncoding=utf-8
username: root
password: ******
jpa:
show-sql: true
database: mysql
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
只需要在pom.xml引入需要的数据库配置,就会自动访问此数据库,如果需要配置其他数据库,可以在application.yml
默认使用org.apache.tomcat.jdbc.pool.DataSource创建连接池
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.1.RELEASE
com.boot
plamanager
0.0.1-SNAPSHOT
plamanager
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-devtools
true
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-maven-plugin
true
项目结构,我建了几个包,如下:
package com.boot.plamanager.pojo;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
@Table(name = "type")
public class Type {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
}
持久层BaseRepository(封装的父类),在util包中
package com.boot.plamanager.util;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.io.Serializable;
@NoRepositoryBean
public interface BaseRepository extends PagingAndSortingRepository,JpaSpecificationExecutor {
}
持久层TypeRepository,在mapper包中
package com.boot.plamanager.mapper;
import com.boot.plamanager.pojo.Type;
import com.boot.plamanager.util.BaseRepository;
public interface TypeRepository extends BaseRepository {
Type findByName(String name);
}
运行项目,会自动的在数据库中创建表和字段。
Repository:最顶层的接口,是一个空的接口,目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别
CrudRepository :是Repository的子接口,提供CRUD的功能
PagingAndSortingRepository:是CrudRepository的子接口,添加分页和排序的功能
JpaRepository:是PagingAndSortingRepository的子接口,增加了一些实用的功能,比如:批量操作等
JpaSpecificationExecutor:用来做负责查询的接口
Specification:是Spring Data JPA提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可
关键字 | 案例 | 效果 |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age 1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate 1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnam noreCase | … where UPPER(x.firstame) = UPPER(?1) |
Druid是阿里巴巴开源的数据库连接池,Druid号称是Java语言中最好的数据库连接池,并且能够提供强大的监控和扩展功能。
支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等。
Druid针对Oracle和MySql做了特别优化,比如:
Oracle的PS Cache内存占用优化
MySql的ping检测优化
Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。
简单SQL语句用时10微秒以内,复杂SQL用时30微秒。
通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。
Druid防御SQL注入攻击的WallFilter,就是通过Druid的SQL Parser分析语义实现的
添加依赖,(我用的1.1.10,版本错了可能有坑)
com.alibaba
druid-spring-boot-starter
1.1.10
com.alibaba
druid
1.1.10
spring:
datasource:
druid:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://cdb-39vuh24q.bj.tencentcdb.com:10059/pladb?useUnicode=true&characterEncoding=utf-8
username: root
password: zhengkai123
type: com.alibaba.druid.pool.DruidDataSource
# 初始化大小,最大,最小
initial-size: 1
max-active: 20
min-idle: 1
# 配置获取连接等待超时的时间
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
max-open-prepared-statements: 20
filters:
commons-log.connection-logger-name: stat,wall,log4j
jpa:
show-sql: true
database: mysql
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
server:
port: 8090
DruidConfig.java,在util包中
package com.boot.placms.util;
import java.sql.SQLException;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration
public class DruidConfig {
private static final Logger logger = LoggerFactory.getLogger(DruidConfig.class);
private static final String DB_PREFIX = "spring.datasource.druid";
@Bean
public ServletRegistrationBean druidServlet() {
logger.info("init Druid Servlet Configuration ");
ServletRegistrationBean servletRegistratiOnBean= new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// IP白名单
servletRegistrationBean.addInitParameter("allow", "192.168.2.25,127.0.0.1");
// IP黑名单(共同存在时,deny优先于allow)
servletRegistrationBean.addInitParameter("deny", "192.168.1.100");
//控制台管理用户
servletRegistrationBean.addInitParameter("loginUsername", "admin");
servletRegistrationBean.addInitParameter("loginPassword", "admin");
//是否能够重置数据 禁用HTML页面上的“Reset All”功能
servletRegistrationBean.addInitParameter("resetEnable", "false");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistratiOnBean= new FilterRegistrationBean(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
@ConfigurationProperties(prefix = DB_PREFIX)
class IDataSourceProperties {
private String url;
private String username;
private String password;
private String driverClassName;
private int initialSize;
private int minIdle;
private int maxActive;
private int maxWait;
private int timeBetweenEvictionRunsMillis;
private int minEvictableIdleTimeMillis;
private String validationQuery;
private boolean testWhileIdle;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean poolPreparedStatements;
private int maxPoolPreparedStatementPerConnectionSize;
private String filters;
private String connectionProperties;
@Bean //声明其为Bean实例
@Primary //在同样的DataSource中,首先使用被标注的DataSource
public DataSource dataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
//configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
System.err.println("druid configuration initialization filter: " + e);
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public int getInitialSize() {
return initialSize;
}
public void setInitialSize(int initialSize) {
this.initialSize = initialSize;
}
public int getMinIdle() {
return minIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public int getMaxActive() {
return maxActive;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public int getMaxWait() {
return maxWait;
}
public void setMaxWait(int maxWait) {
this.maxWait = maxWait;
}
public int getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
}
public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictiOnRunsMillis= timeBetweenEvictionRunsMillis;
}
public int getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
}
public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
public String getValidationQuery() {
return validationQuery;
}
public void setValidationQuery(String validationQuery) {
this.validatiOnQuery= validationQuery;
}
public boolean isTestWhileIdle() {
return testWhileIdle;
}
public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}
public boolean isTestOnBorrow() {
return testOnBorrow;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow= testOnBorrow;
}
public boolean isTestOnReturn() {
return testOnReturn;
}
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn= testOnReturn;
}
public boolean isPoolPreparedStatements() {
return poolPreparedStatements;
}
public void setPoolPreparedStatements(boolean poolPreparedStatements) {
this.poolPreparedStatements = poolPreparedStatements;
}
public int getMaxPoolPreparedStatementPerConnectionSize() {
return maxPoolPreparedStatementPerConnectionSize;
}
public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
this.maxPoolPreparedStatementPerCOnnectionSize= maxPoolPreparedStatementPerConnectionSize;
}
public String getFilters() {
return filters;
}
public void setFilters(String filters) {
this.filters = filters;
}
public String getConnectionProperties() {
return connectionProperties;
}
public void setConnectionProperties(String connectionProperties) {
this.cOnnectionProperties= connectionProperties;
}
}
}
Druid 数据源属性
属性(Parameter) | 默认值(Default) | 描述(Description) |
---|---|---|
initialSize | 3 | 初始化配置 |
minIdle | 3 | 最小连接数 |
maxActive | 15 | 最大连接数 |
maxWait | 5000 | 获取连接超时时间(单位:ms) |
timeBetweenEvictionRunsMillis | 90000 | 连接有效性检测时间(单位:ms) |
testOnBorrow | false | 获取连接检测 |
testOnReturn | false | 归还连接检测 |
minEvictableIdleTimeMillis | 1800000 | 最大空闲时间(单位ms) |
testWhileIdle | true | 在获取连接后,确定是否要进行连接空间时间的检查 |
访问druid页面,输入类中配置的账号密码登录:
http://localhost:8090/druid/index.html
添加依赖
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
修改application.yml文件,添加mybatis配置
spring:
datasource:
druid:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://cdb-39vuh24q.bj.tencentcdb.com:10059/pladb?useUnicode=true&characterEncoding=utf-8
username: root
password: zhengkai123
type: com.alibaba.druid.pool.DruidDataSource
# 初始化大小,最大,最小
initial-size: 1
max-active: 20
min-idle: 1
# 配置获取连接等待超时的时间
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
max-open-prepared-statements: 20
filters:
commons-log.connection-logger-name: stat,wall,log4j
jpa:
show-sql: true
database: mysql
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
server:
port: 8090
## 该配置节点为独立的节点,若将这个配置放在spring的节点下,会导致配置无法被识别
mybatis:
mapper-locations: classpath:sqlmap/*.xml #注意:一定要对应mapper映射xml文件的所在路径
type-aliases-package: com.boot.placms.pojo # 注意:对应实体类的路径
接下来就是一系列的开发流程,新建了一个jpa包,把TypeRepository放在了jpa包下,做好分类而已,在mapper包中新建TypeMapper.java接口
package com.boot.placms.mapper;
import com.boot.placms.pojo.Type;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* @ 描 述 :
* @ 作 者 : 一念〃
* @ 时 间 : 22:40 2018/12/28
* @ 备 注 :
*/
@Mapper
public interface TypeMapper {
Type findByName(@Param("name") String name)throws Exception;
}
新建service包,在其中新建service接口,ITypeService.java
package com.boot.placms.service;
import com.boot.placms.pojo.Type;
/**
* @ 描 述 :
* @ 作 者 : 一念〃
* @ 时 间 : 22:34 2018/12/28
* @ 备 注 :
*/
public interface ITypeService {
Type findByName(String name);
}
在service包中新建impl包,用于实现类的存放,TypeServiceImpl.java
package com.boot.placms.service.impl;
import com.boot.placms.mapper.TypeMapper;
import com.boot.placms.pojo.Type;
import com.boot.placms.service.ITypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @ 描 述 :
* @ 作 者 : 一念〃
* @ 时 间 : 22:35 2018/12/28
* @ 备 注 :
*/
@Service
public class TypeServiceImpl implements ITypeService {
@Autowired
private TypeMapper typeMapper;
/**
* 根据名字查询返回对象
* @param name
* @return
*/
@Override
public Type findByName(String name) {
Type byName = null;
try {
byName = typeMapper.findByName(name);
} catch (Exception e) {
e.printStackTrace();
}
return byName;
}
}
新建controller包,控制器的存放,TypeController.java
package com.boot.placms.controller;
import com.boot.placms.pojo.Type;
import com.boot.placms.service.ITypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @ 描 述 :
* @ 作 者 : 一念〃
* @ 时 间 : 22:36 2018/12/28
* @ 备 注 :
*/
@Controller
@RequestMapping("/test")
public class TypeController {
@Autowired
private ITypeService typeService;
@RequestMapping("/name")
public Type name(@RequestParam(required=false, value="name") String name){
return typeService.findByName(name);
}
}
在resources文件夹下新建sqlmap包,存放mabatis的xml文件,TypeMapper.xml,这个文件名与接口名一致,不然可能会报错的
看一下目录结构:
接下来是测试mybatis,在controller中打个断点,然后debug模式启动,访问controller
http://127.0.0.1:8090/test/name?name=赵山河
访问后进入断点:
使用调试工具,New Watch查看对应的值,输入typeService.findByName(name)后回车,查看所返回的对象
可以看到id是1,name是赵山河,与我们数据库的数据一致,mybatis配置成功
需要注意的是:
上边我的mabatis的xml文件存放在resources中的sqlmap文件夹下,就这么写就行了:
如果想放在java包下的mapper包下,和mapper接口放在一起,则需要改成:
mybatis:
mapper-locations: classpath:com/boot/placms/mapper/*.xml #注意:一定要对应mapper映射xml文件的所在路径
type-aliases-package: com.boot.placms.pojo # 注意:对应实体类的路径
而后在启动类中添加mapper扫描,如果放在resources下则不需要这样:
@MapperScan("com.boot.placms.mapper")
// 如果要扫描多个,用下面这种写法
//@MapperScan(basePackages={"com.boot.placms.mapper", "com.boot.placms.dao"})
还有可能出现的一个错误就是:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):com.boot.placms.mapper.TypeMapper.findByName
引起的原因:
就是mybatis报错,哪里没有配置好,需要检查的地方:
如果还不行,看一下target文件夹下,xml文件有没有编译:
我的是放在resources下的,会被编译的,放在java包下的我没试过,如果没有被编译,手动在pom文件中的build节点下添加:
src/main/java
**/*.xml
true
总之,是自己引起的错误,与idea编辑器和mybatis无关,自己没整明白而已。
截止到此,项目已经可以开始撸代码了,保存一份,以后拿来直接用。
下载链接:
链接: https://pan.baidu.com/s/15m-lO7onfN23Jb4oNZa-kQ
提取码: n7xu