SpringBoot创建项目
导入
首先把html放到template文件夹中,可以使用Thymeleaf模板功能。如果放到static文件夹下就不能用。
同样,dao,entities,controller也是放到相应的文件夹下
然后我是在HelloController中修改了”"和“\index”的Mapping,修改启动主页:
1 |
|
- 500错误:未在pom.xml引入spring-boot-starter-thymeleaf启动器依赖
SpringBoot配置文件
首先在pom.xml中引入配置文件解释器:
1 | <!--配置文件处理器--> |
引入了之后就会有提示了。
application文件举例
配置文件默认是application.properties或者是application.yml
举例:
application.properties
1 | #配置person的值,与yml语法不一样 |
application.yml
1 | server: |
yml一定要在 “冒号:” 后面加个空格,不然识别不了。
yml是缩进控制的语法,大小写敏感。
占位符,yml和properties都支持
1 | #随机uid |
Profile
SpringBoot支持配置文件多Profile,形式如application-dev.yml(开发环境配置文件),application-pro.properties(生产环境配置文件)。
这样命名之后可以直接通过一些方式来指定使用哪一个配置文件。
这里的名字是可以随便起的(符合规范别xjb起就行)。
yml多文档块方式
1 | #我们假设不同环境使用的端口不同 |
指定profile
配置文件中直接写,比如上面的
spring.profiles.active=prod
命令行中指定参数:
在项目打jar包之后,使用命令行进行部署时可以像这个命令一样指定profiles:java -jar jar包名.jar -spring.profiles.active=dev ;
或者可以在IDEA中运行设置,Edit Configuation中的Program arguments填写spring.profiles.active=dev
虚拟机参数:
在Edit Configuations中的VM options::-Dspring.profiles.active=dev
配置文件加载位置
4个位置:
优先级从高到低,属性不同互补,相同高的覆盖低的
-file: /config/ 当前文件夹下的config文件夹下(比如整个项目文件夹下)
-file: / 文件夹下根目录里
-classpath: /config/ 类目录下的config文件夹下(IDEA里面的
-classpath: / 类目录下的根目录里指定配置文件路径
在默认的全局配置文件中可以写:
spring.config.loactions=G:/application.properties
配置文件加载优先级
我们重点关注以下几个顺序,优先级都是从高到低的:
命令行参数
jar包外向jar包内进行寻找
优先加载带profile的
jar包外的application-{profiles}配置文件(properties或yml)
jar包内的application-{profiles}配置文件
之后是不带profile的
jar包外的application.properties或yml
jar包内的application.properties或yml
@Configuration注解类上的@PropertySource
自动配置的原理
这里涉及到比较底层的Spring注解,先暂时跳过了。
SpringBoot日志
日志分为日志门面(日志的抽象层)和日志实现
SpringBoot:底层是Spring框架,Spring框架默认使用JCL(很久没有更新过了)
SpringBoot选用的是SLF4(门面)和logback(实现)
1 | //记录器 |
1 | 日志输出格式: |
SpringBoot修改日志的默认配置
1 | trace = |
logging.file | logging.path | Example | Description |
---|---|---|---|
(none) | (none) | 只在控制台输出 | |
指定文件名 | (none) | my.log | 输出日志到my.log文件 |
(none) | 指定目录 | /var/log | 输出到指定目录的 spring.log 文件中 |
整合JDBC
- 添加pom依赖
- 配置文件中添加数据库驱动,用户名,密码,url
- 新建DataSource对象getConnection()一下,来看看是否连接成功
新建项目时勾选MySQL和JDBC:
pom.xml中jdbc和mysql的依赖
1 | <dependency> |
配置文件
然后在配置文件中,增加数据库连接的属性:
1 | spring: |
遇到问题:
抛出The server time zone value '�й���ʱ��' is unrecogni
错误
原因是因为使用了Mysql Connector/J 6.x以上的版本,然后就报了时区的错误
1 | 将原来的连接: |
添加?serverTimezone=UTC即可解决。
测试
SpringBoot测试类:
1 |
|
使用阿里数据源Druid
添加依赖
在配置文件中增加属性,特别是type修改使用数据源
编写配置类
数据源是一种提高数据库连接性能的常规手段,它会创建一个数据连接池,由它来管理数据库连接,而不需要手动的频繁打开或关闭数据库连接从而提高了性能。
DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,据说是目前最好的连接池。
上面SpringBoot默认的数据源是com.zaxxer.hikari.HikariDataSource,然后我们将其修改为alibaba的Druid。
在上面的基础上进行修改:
pom.xml引入依赖
1 | <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> |
具体依赖还有各种版本可以去Maven Repository网站搜Druid
修改配置文件
1 | spring: |
主要是修改type,改变数据源。然后进行其他具体参数设置。
编写配置类DruidConfig
1 |
|
总的来说,就是写了一个Servlet和一个Filter注入到容器中。
Servlet是用来处理请求,显示Druid的界面;
Filter是拦截网页的请求(部分静态资源除外),用来统计监控数据。
servlet是用于显示druid管理界面,并对其中的一些参数进行设置;
filter是对请求进行拦截,通过拦截对数据进行统计。
编写完配置类之后,要在主程序入口Application上面添加@ServletComponentScan注解扫描所有的Servlet。
访问页面
访问上面设置的servlet地址即可,localhost:8080/druid
,会自动跳转到登录页面,其中的账号密码就是上面设置的参数中的loginUsername和loginPassword。
PS:使用druid要添加log4j日志依赖,因为druid用到了这玩意,不加会报错
整合MyBatis
整合MyBatis依然在上面的基础上进行。
有两种方式:
1. 注解方式
2. xml配置文件方式
自我感觉整合MyBatis的核心就是写Mapper
何为ORM框架/Hibernate/…
先做杂项工作:编写两个POJO普通类,同时数据库中建两个相应的表。
注解版
编写Mapper
1 | //指定这是一个操作数据库的mapper |
关于注解中的值和参数的关系,比如#{id},对应的是下面参数中同名的参数(比如上面的Integer id);或者是下面参数是对象,对象中的同名的属性值:
使用对象
如果我们使用普通的java对象作为查询条件的参数:
1
2 @Insert("INSERT INTO T_USER(NAME, PASSWORD, PHONE) VALUES(#{name}, #{password}, #{phone})")
int insertByUser(User user);只需要语句中的#{name}、#{age}就分别对应了User对象中的name和age属性。
1
2
3
4
5 User u = new User();
u.setName("赵六");
u.setPassword("12312312");
u.setPhone("13888888888");
userMapper.insertByUser(u);
@Insert("INSERT INTO T_USER(NAME, PASSWORD, PHONE) VALUES(#{name}, #{password}, #{phone})")
int insertByUser(User user);
只需要语句中的#{name}、#{age}就分别对应了User对象中的name和age属性。
User u = new User();
u.setName("赵六");
u.setPassword("12312312");
u.setPhone("13888888888");
userMapper.insertByUser(u);
关于这里的传参方式还有几种,比如@Param注解、使用Map、还有上面的使用对象。具体参见这个CSDN博客。
编写Mapper:
- 使用@Mapper注解来说明这是个Mybatis的Mapper映射,然后写成接口?
- 自定义方法,名字随意,方法参数和注解相对应(如上传参方式)
- 注解@Insert,@Select等等,在这种注解中写相应的SQL语句(参数如上)。
编写Controller
1 |
|
编写Controller来进行测试,调用Mapper中的方法,进行增删改查。注意这里用URL传参的方式。
XML配置文件版
编写Mapper接口
这里的Mapper类不需要写注解,只是包含相应的自定义方法,还有方法的参数。其他的相关东西都在xml里。
1 | //需要用@Mapper或者@MapperScan将接口扫描装配到容器中 |
编写mybatis-config.xml
在里面进行各种配置。
1 |
|
这里主要是解决了d_id和dId不同的问题,如果不加这个配置,那么在数据库中的d_id和类中的dId不会匹配。
编写Mapper.xml
1 |
|
注意的地方:
- namespace:Mapper类名具体的路径
- id:应该是和方法名相对应
- resultType:返回值类型,也是具体的类路径;返回值为空就不用写
- 在相应的比如
<select></select>
编写SQL语句即可,值和参数仍然和上面的一样。
修改application.yml配置文件
1 | #mybatis配置xml方式,xml所在路径 |
在配置文件中加如上属性,指定mybatis的xml配置文件所在路径。
整合JPA
整合JPA时也可将数据源换为Druid,但是这里就没再换。
何为JPA
JPA是Java持久化API,定义了一系列对象持久化的标准,而hibernate是当前非常流行的对象持久化开源框架,Spring boot就默认集成了这种框架,加速web应用开发。
spring-boot-starter-data-jpa的启动器中继承了Hibernate。
这里我们用的Spring Data JPA是Spring基于ORM框架、JPA规范的基础上封装的一套JPA应用框架,是基于Hibernate之上构建的JPA使用解决方案。
JPA == Java Persistence API(Java 持久层 API):用于对象持久化的 API
作用:使得应用程序以统一的方式访问持久层
JPA 是 Hibernate 的一个抽象,就像 JDBC 和 JDBC 驱动的关系。JPA是一种规范,而Hibernate是JPA的一个实现。
参考:
整合JPA
pom.xml依赖
1 | <dependency> |
PS:spring-boot-starter-data-jpa包括了Hibernate。
application.yml配置文件
1 | spring: |
前面DataSource的配置和以前一样,url用户名密码驱动等。
下面的overriding如果不写的话启动不了,根据控制台建议写上的。
实体类
重点在实体类的注解上:
1 | //使用JPA注解配置映射关系 |
- @Entiy:说明这是一个POJO类
- @Table:指明这个类和数据库中哪张表映射
- @Id:表示这个属性在表中是主键
- @GeneratedVlue:说明了主键的生成方式
- @Column:指定这个属性和表中哪个字段对应
继承JpaRepository接口
1 | //JpaRepository后面的泛型:要操作的实体类,以及主键的类型 |
Controller 调用
1 |
|
这里调用的话就直接自动注入一个Repository,然后用它来调用相应的方法如findAll()、getOne()等等即可(Hibernate会自动生成数据库语句,不用手动写)。
在请求的同时,因为在application.yml中添加了show-sql: true
属性,所以说console会打印出SQL语句:
SpringBoot 注解
/hello请求
@SpringBootApplication
标注一个主程序类,表明这是一个SpringBoot应用,程序开始入口1
2
3
4
5
6
7
8
public class SpringBoot01HelloworldQuickApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot01HelloworldQuickApplication.class, args);
}
}@ResponseBody
表明这是一个响应
表示该方法的返回结果直接写入HTTP response body中
一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@responsebody后,会直接返回json数据。@RequestMapping(“/hello”)
响应/hello请求@Controller
是个Spring、SpringMVC的注解,@Controller 控制层,@Service 服务层,@Repository 持久层;或者这里
@RestController:
用于标注控制层组件(如struts中的action),包含**@Controller和@ResponseBody**。
1 | /*@ResponseBody |
配置文件,使用properties或yml注入Bean
@Component
泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Component和@Bean都是用来注册Bean并装配到Spring容器中,但是Bean比Component的自定义性更强。可以实现一些Component实现不了的自定义加载类。@PropertySource(value = {“classpath:person.properties”})
从指定的路径中导入配置文件(不指定这个注解的话,会自动从默认的全局配置文件application.properties中导入)@ConfigurationProperties(prefix = “person”)
将配置文件(比如application.properties)中的person属性的值与当前类的属性绑定@Value(“${person.last-name}”)
将这个值绑定到标注下面的属性上1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Person {
//Value赋值,一个一个的
// $ 取资源文件中的值
//@Value("${person.last-name}")
private String lastName;
// # 计算表达式
//@Value("#{11*2}")
private Integer age;
//直接赋值
//@Value("true")
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> list;
private Dog dog;
......
}
- @ConfigurationProperties和@Value的比较
- 一般@Value导入时,是一个值一个值的导入,而@ConfigurationProperties是一批导入。
- @Value支持SPEL,而@ConfigurationProperties比如
- @Value(${person.last-name}):绑定person.last-name到当前属性
- @Value(#{11*2}):计算11*2,就是22
- @Value(“true”):直接赋值为 true
@Value不支持松散语法。
- 在松散语法中,last-name与lastName是一样的,-n就是大写的N,而不支持松散语法的话就不一样
@Value不支持JSR303数据校验
- 就是说下面的这个@Email,会校验绑定的这个属性是否符合格式
- 加上@Email之前,需要一个这个@Validated注解
- @Email:校验数据是否邮箱格式
- 如果校验不通过的话会抛IllegalStateException异常,数据不能绑定
- @Validated的详细使用
@Value不支持复杂类型封装
配置类
@ImportResource(locations = {“classpath:beans.xml”})
标注在一个配置类上
1
2
3
4
5
6
7
8
9
public class SpringBoot01HelloworldQuickApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot01HelloworldQuickApplication.class, args);
}
}导入spring的配置文件,bean.xml
1
2
3
4
5
6
7
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloService" class="com.song.springboot.service.HelloService"></bean>
</beans>这个xml的作用就是给HelloService类中注入一个id为helloService的Bean,可以在test中用以下来验证:
1
2
3
4
5
6
7
8
ApplicationContext ioc;
public void testHelloService(){
boolean b = ioc.containsBean("helloService");
System.out.println(b);
}@Autowired
自动注入。可以对成员变量、方法和构造函数进行标注。
@Autowired
注解的意思就是,当Spring发现@Autowired
注解时,将自动在代码上下文中找到与其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。@Confgiuration
指出该类是 Bean 配置的信息源,相当于XML中的
,一般加在主类上。说明这个是个配置类。 @Bean
相当于XML中的
,放在方法的上面,而不是类,意思是产生一个bean,并交给spring管理。 1
2
3
4
5
6
7
8
9//说明这是个配置类,返回一个HelloService对象注入到容器中,最后ioc容器中会含有一个helloService
public class MyAppConfig {
public HelloService helloService(){
return new HelloService();
}
}
遇到的一些问题解决
添加schema-all.sql到resources中,不会自动建表
错误:
添加schema-all.sql到resources中,不会自动建表
解决:
在application.properties配置文件中添加:
1 | ## 加这个,不然不会执行schema-all或者下面自定义sql脚本 |
同时,如果加schema自定义sql位置,也是需要加是这个always属性的
1 | ## 设置默认的sql位置 |
修改Durid,新建config配置绑定属性:
报错:
1 | Failed to bind properties under 'spring.datasource' to javax.sql.DataSource |
原因:
在yml配置文件中,设置的属性:
1 | ## 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 |
其中filters引用了log4j,但是pom.xml中没有,所以说报错
解决:
在pom.xml中添加log4j的依赖:
1 | <dependency> |
SpingBoot+Druid,404错误
错误:
网页404:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Sep 28 09:21:10 CST 2019
There was an unexpected error (type=Not Found, status=404).
No message available
原因:
1 | //1.配置一个管理后后台的servlet,这个Bean加到容器中 |
其中的ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/");
,第二个参数,urlMappings写错了。应该是"/druid/*"
,是druid 路径下所有映射。
修改:
1 | ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); |
即可。
整合JPA,报错Caused by: org.hibernate.AnnotationException: No identifier specified for entity:
错误:
这个前面还有个错误,好像是什么不能注入容器,根据console提示修改一下yml就行啦,加上:
1
2
3 spring:
main:
allow-bean-definition-overriding: true大概是在容器中把我们写的UserRepository注入进去覆盖原来自有的?
启动SpringBoot时报错:
1 | org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: com.song.springboot.entity.User |
原因:
百度了半天,都在说是实体类的注解写错了,需要加上主键的@Id,我对了半天也没发现错误。最终发现:
1 | import org.springframework.data.annotation.Id; |
还真是@Id的问题,因为我加@Id的时候导包导入错了,不是springframework的@Id注解而是persistence里面的。
解决:
删掉上面那个id的import就行。
JPA查询报错
错误:
Controller中查找方法:
1 | //查找用户 |
访问这个url然后报错:
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.song.springboot.entity.User$HibernateProxy$j7VI3Nk2["hibernateLazyInitializer"])
原因:
因为返回值是个实体类对象的原因。
hibernate会给每个被管理的对象加上hibernateLazyInitializer属性,同时struts-jsonplugin或者其他的jsonplugin都是如此。
因为jsonplugin用的是java的内审机制,hibernate会给被管理的pojo加入一个hibernateLazyInitializer属性。jsonplugin通过java的反射机制将pojo转换成json,会把hibernateLazyInitializer也拿出来操作。但是hibernateLazyInitializer无法由反射得到,也就是说从对象中无法获取,所以就抛异常了。
解决:
在User实体类中加入如下注解:
1 | //使用JPA注解配置映射关系 |
在类上声明的@JsonIgnoreProperties,是忽略Hibernate的延迟加载的一些属性”hibernateLazyInitializer”, “handler”, “fieldHandler”,这些属性在实体类里没有所以要忽略掉,否则会报错。
Java反射来输出对象的所有属性
1 | public static void testReflect(Object model) throws Exception { |
使用sql将一个表的数据导入另一个表:
1 | insert into jc_rw(guid,rwid,xmbh,xmmc,xfsj) (select rwid,rwid,xmbh,xmmc,xfsj from jc_db_task); |
设置一个表中的某一列全部为这个数据:
1 | update jc_rw set cdrwks='监测科'; |
整合Mybatis-Plus和Lombok
主要是mybaits-plus
修改pom文件,添加依赖
修改yml配置文件,将mybatis的配置删除,增加mybatis-plus配置
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## MyBatis配置
## https://baomidou.com/config/
mybatis-plus:
## 对应的 XML 文件位置
mapperLocations: classpath*:mapper/**/*Mapper.xml
## 实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.ruoyi.**.domain
## 针对 typeAliasesPackage,如果配置了该属性,则仅仅会扫描路径下以该类作为父类的域对象
#typeAliasesSuperType: Class<?>
## 如果配置了该属性,SqlSessionFactoryBean 会把该包下面的类注册为对应的 TypeHandler
#typeHandlersPackage: null
## 如果配置了该属性,会将路径下的枚举类进行注入,让实体类字段能够简单快捷的使用枚举属性
#typeEnumsPackage: null
## 启动时是否检查 MyBatis XML 文件的存在,默认不检查
checkConfigLocation: false
## 通过该属性可指定 MyBatis 的执行器,MyBatis 的执行器总共有三种:
## SIMPLE:该执行器类型不做特殊的事情,为每个语句的执行创建一个新的预处理语句(PreparedStatement)
## REUSE:该执行器类型会复用预处理语句(PreparedStatement)
## BATCH:该执行器类型会批量执行所有的更新语句
executorType: SIMPLE
## 指定外部化 MyBatis Properties 配置,通过该配置可以抽离配置,实现不同环境的配置部署
configurationProperties: null
configuration:
## 自动驼峰命名规则(camel case)映射
## 如果您的数据库命名符合规则无需使用 @TableField 注解指定数据库字段名
mapUnderscoreToCamelCase: true
## 默认枚举处理类,如果配置了该属性,枚举将统一使用指定处理器进行处理
## org.apache.ibatis.type.EnumTypeHandler : 存储枚举的名称
## org.apache.ibatis.type.EnumOrdinalTypeHandler : 存储枚举的索引
## com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler : 枚举类需要实现IEnum接口或字段标记@EnumValue注解.
defaultEnumTypeHandler: org.apache.ibatis.type.EnumTypeHandler
## 当设置为 true 的时候,懒加载的对象可能被任何懒属性全部加载,否则,每个属性都按需加载。需要和 lazyLoadingEnabled 一起使用。
aggressiveLazyLoading: true
## MyBatis 自动映射策略
## NONE:不启用自动映射
## PARTIAL:只对非嵌套的 resultMap 进行自动映射
## FULL:对所有的 resultMap 都进行自动映射
autoMappingBehavior: PARTIAL
## MyBatis 自动映射时未知列或未知属性处理策
## NONE:不做任何处理 (默认值)
## WARNING:以日志的形式打印相关警告信息
## FAILING:当作映射失败处理,并抛出异常和详细信息
autoMappingUnknownColumnBehavior: NONE
## Mybatis一级缓存,默认为 SESSION
## SESSION session级别缓存,同一个session相同查询语句不会再次查询数据库
## STATEMENT 关闭一级缓存
localCacheScope: SESSION
## 开启Mybatis二级缓存,默认为 true
cacheEnabled: true
global-config:
## 是否打印 Logo banner
banner: true
## 是否初始化 SqlRunner
enableSqlRunner: false
dbConfig:
## 主键类型
## AUTO 数据库ID自增
## NONE 空
## INPUT 用户输入ID
## ASSIGN_ID 全局唯一ID
## ASSIGN_UUID 全局唯一ID UUID
idType: AUTO
## 表名前缀
tablePrefix: null
## 字段 format,例: %s,(对主键无效)
columnFormat: null
## 表名是否使用驼峰转下划线命名,只对表名生效
tableUnderline: true
## 大写命名,对表名和字段名均生效
capitalMode: false
## 全局的entity的逻辑删除字段属性名
logicDeleteField: null
## 逻辑已删除值
logicDeleteValue: 1
## 逻辑未删除值
logicNotDeleteValue: 0
## 字段验证策略之 insert,在 insert 的时候的字段验证策略
## IGNORED 忽略判断
## NOT_NULL 非NULL判断
## NOT_EMPTY 非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断)
## DEFAULT 默认的,一般只用于注解里
## NEVER 不加入 SQL
insertStrategy: NOT_NULL
## 字段验证策略之 update,在 update 的时候的字段验证策略
updateStrategy: NOT_NULL
## 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
selectStrategy: NOT_NULL