SpringBoot学习笔记
SpringBoot学习笔记
简化spring应用初始化搭建和开发过程
Springboot=Springmvc(控制器Controller) + Spring(工厂)
约定:
- springboot项目中有且只有一个入口类,类名:推荐:xxxApplication.java
- 入口类必须在所有子包之上
- 入口类中必须存在一个启动项目的main函数
- springboot项目约定必须在项目根目录中存在一个application.yml或者application.properties配置文件
Hello World探究
1.pom文件
1.父项目
1 |
|
springboot的版本仲裁中心,真正管理springboot应用里面的所有依赖版本,
1 |
|
2.导入的依赖
1 |
|
spring-boot-starter:spring-boot场景启动器,帮我们导入了web模块正常运行所依赖的组件
springboot将所有的场景都抽取出来,做出一个个的starters(启动器),只需要在项目里面导入依赖就行,根据场景需要而导入。
2.主程序类,主入口类
@SpringBootApplication:springboot应用标注在某个类上说明这个类是springboot的主配置类,springboot就应该运行这个类的main方法来启动springboot应用
1 |
|
@SpringBootConfiguration:springboot配置类
@EnableAutoConfiguration:开启自动配置功能
1 |
|
@AutoConfigurationPackage:自动配置包
@Import:spring底层注解,给容器导入一个组件
将主配置类所在包下面的所有组件扫描到spring容器
EnableAutoConfigurationImportSelector:导入哪些组件的选择器,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中,会给容器中导入非常多的自动配置类
springboot在启动的时候从类路径下的META-INF/spring.factories获取EnableAutoConfiguration指定值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作
配置文件
1.springboot使用一个全局的配置文件,配置文件名是固定的
- application.properties
- application.yml
配置文件的作用:修改spring自动配置的默认值,springboot在底层给我们配置好
YAML(YAML Ain’t Markup Language),以数据为中心,比xml、json更适合做配置文件
例子:
YAML:
1 |
|
XML:
1 |
|
2.基本语法
基本语法
k(空格)v:表示一对键值对,空格必须要有
以空格的缩进来控制层级关系,只要是左对齐的一列数据,都是同一个层级的
属性和值都是大小写敏感
值的写法:
字面量:普通的值(数字、字符串、布尔)
k:v:字面直接来写
字符串默认不用加上单引号或者双引号
双引号:不会转义字符串里面的特殊字符
name: “we \n rng” 输出:we
rng
单引号:会转义特殊字符
name: ‘we \n rng’ 输出:we \n rng
对象(属性和值,键值对):
对象还是k:v的方式
friends:
name:zhangsan
age:20
行内写法:
friends:{name:zhangsan,age:20}
数组(List,Set)
用 -值表示数组中的一个元素
animals:
-dog
-cat
-bird
行内写法:
animals:[dog,cat,bird]
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 需要一个一个的写 |
松散语法绑定 | 支持 | 不支持 |
SpEL | 不支持 person.age=#{11*2} | 支持 @Value(“#{11*2}”) |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
- 不管配置文件是yml还是properties都可以获取到值
- 如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的值,就用@Value()
- 如果说,我们专门有一个javabean来和配置文件进行映射,那就用@ConfigurationProperties()
1 |
|
拆分配置文件
1 |
|
可能有本地生产环境配置文件、实际上线配置文件:
在application.yml中指定 spring-profiles-active
1 |
|
外部配置文件:
在tomcat配置:environment下的program arguments中配置如下
–spring.config.location=D:/IDEA/测试springboot外部配置文件/application-out.yml
spirngboot 微框架 = spring(工厂) 用来管理项目对象 + springmvc(控制器)
微:快速开发 通过遵守默认约定 简化项目中样板化配置
spring工厂创建对象
基于配置文件形式创建对象
1
<bean id="" class="">
基于注解形式方式创建对象
1
2
3
4@Compoent 作用:在工厂中创建对象
@Controller 创建控制器注解
@Service 创建业务层注解
@Responsity 创建Dao层注解
springboot创建对象
使用原始spring框架中注解创建对象 只能创建单个对象
1
2
3
4@Compoent 作用:在工厂中创建对象
@Controller 创建控制器注解
@Service 创建业务层注解
@Responsity 创建Dao层注解使用配置方式创建对象 可以创建多个对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Configuration 修饰范围用在类上,相当于spring中的spring.xml,代表这个类是一个springboot中的配置类
@Bean 创建对象,相当于spring.xml中的bean标签
@Configuration
public class BeanConfig(){
@Bean
public User user(){
return new User();
}
@Bean
public Order order(){
return new Order();
}
}
spring框架中属性注入
引用类型注入
1 |
|
八种基本类型+String类型
1 |
|
Springboot属性注入
配置文件@Value
配置文件加上@ConfigurationProperties,必须要有set方法
Springboot框架如何整合mybatis框架?
引入依赖
springboot-starter-web
mysql相关 驱动 数据源
mybatis相关 mybatis-spring-boot-starter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.4</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!-- mybatis-spring-boot-starter-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>书写配置
a.开启注解扫描
b.创建数据源
指定数据源类型、驱动、协议、用户名、密码
c.创建SqlSessionFactory
指定mapper文件配置
指定实体类所在包位置 、起别名
d.创建Dao
指定Dao接口所在包
1
2
3
4
5
6
7
8
9
10
11
12
13#整合mybatis相关配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot?characterEncoding=UTF-8
username: root
password: 123456
#指定mapper配置文件位置
mybatis:
mapper-locations: classpath:/mapper/*.xml
#起别名
type-aliases-package: yxnu.edu.entity1
2
3
4
5
6
7
8
9@SpringBootApplication
@MapperScan("yxnu.edu.dao") //用在类上,扫描dao接口所在包,同时将所有dao接口在工厂中创建对象
public class Springboot02Application {
public static void main(String[] args) {
SpringApplication.run(Springboot02Application.class, args);
}
}测试
springboot本地测试
引入依赖
1
2
3
4
5<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>编写测试类
1
@SpringBootTest 用在类上,启动本地spring环境测试
可以写一个类让其他类来继承它,这样就不用每次都写@SpringBootTest
1
2
3@SpringBootTest
public class BasicTest {
}继续BasicTest
1
2
3
4
5
6
7
8public class UserServiceTests extends BasicTest{
@Autowired
private UserService userService;
@Test
public void test1(){
userService.findAll().forEach(list-> System.out.println(list));
}
}
日志处理
springboot集成的是logback日志
分为8个级别:级别越高,输出的信息越多,ALL级别最高
- OFF、FATAL 、ERROR、WARN、INFO、DEBUBG、TRACE、ALL
分类:一种是rootLogger(全局日志),用来监听项目中所有的运行日志,包括引入依赖jar中的内容
一种是logger(子日志),用来监听项目中指定包中的日志信息
默认是INFO
级别
1 |
|
1 |
|
或者使用lombok
1 |
|
1 |
|
切面编程
Aspect(切面) = Advice(通知) + 切入点(Pointcut)
- 引入aop依赖
- 在springboot项目中新建config配置包
1 |
|
切入点函数:
execution:最宽泛
within:某个类
annotion:只有在自定义的注解方法用上才有效
文件上传
1 |
|
1 |
|
文件下载
- 确定项目中哪些资源可以被下载
- 将可以被下载的资源放入服务器指定位置
- 开发一个下载页面,链接
1 |
|
1 |
|
1 |
|
拦截器 interceptor
注意:只能拦截controller相关的请求,底层是aop,java web中的filter可以拦截所有
作用:将controller中共有的代码放入到拦截器中执行,减少controller中代码冗余
特性:如果请求前配置了拦截器,先执行拦截器,放行后执行controller,controller执行完后回到拦截器
拦截器开发:
1 |
|
1 |
|
1 |
|
springboot项目两种部署方式
war部署
1
2
3
4
5
6
7
8
9
10
11
12
131.springboot默认为jar,修改为war,在pom.xml中加入<packing>war<packing>
2.排除内嵌tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provied</scope>
</dependency>
如果还有其他依赖,修改范围为provied
3. 修改入口类
4.springboot内嵌的tomcat端口号失效,项目名等也会失效
5.放到tomcat中,启动tomcat会自动解压运行,按照端口访问即可jar部署
1
21.打包成jar
2.java -jar 项目名
RESTFUL API
设计原则
使用名词而不是动词
Get方法和查询参数不应该涉及状态改变
使用复数名词
使用子资源表达关系
1
2例子:
GET /users/001/cars/007 代表user 001的007号车使用HTTP头声明序列化格式
1
2
3如:
Accept 定义可接受的响应格式,如json
Content-type 定义请求格式,如json为集合提供过滤、排序、选择、分页等功能
1
2
3
4
5例子:
GET /cars?color=red 返回红色的车
GET /cars?sort=price 返回根据价格排序的car集合
GET /cars?fields=price,color,model 移动端显示其中一些字段,降低API网络流量
GET /cars?offset=10&limit=5 分页版本化你的API
1
2/users/api/v1
/users/api/v2使用HTTP状态码处理错误
1
状态码+错误信息,缺一不可,正确的话数据+状态码
使用
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@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {
/**
* @ResponseEntity springmvc封装的一个专用于restful响应类 ,这个类中可以自定义响应体以及状态码
* HttpStatus springmvc封装的一个枚举类型类,为网络中的状态码
*/
//查询某个用户
//@PathVariable代表从请求路径中获取参数
@GetMapping("/{id}")
public ResponseEntity<User> queryBYId(@PathVariable("id") Integer id) {
log.debug("本次id;{}", id);
User user = new User("112", 18, new Date(), 22.22);
return new ResponseEntity<>(user, HttpStatus.OK);
}
//查询所有用户
@GetMapping()
public ResponseEntity<List<User>> queryAll() {
List<User> list = new ArrayList<>();
list.add(new User("777", 22, new Date(), 77.77));
list.add(new User("888", 22, new Date(), 788.77));
return new ResponseEntity<>(list, HttpStatus.OK);
}
//添加用户
//@RequestBody 表示把前端接收的json格式的数据转换为对象
@PostMapping()
public ResponseEntity<Void> saveUser(@RequestBody User user) {
log.debug("user对象:{}", user);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);//没有内容
}
//更新用户
@PutMapping("{id}")
public ResponseEntity<Void> updateUser(@PathVariable("id") Integer id, @RequestBody User user) {
log.debug("id:{}", id);
log.debug("user对象:{}", user);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
//删除用户
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable("id") Integer id) {
log.debug("id值:{}", id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}测试接口
使用postman来测试
异常处理
当controller中方法在执行过程中出现异常,我们应该如何处理这种异常
传统方式开发异常处理
1
HandlerExceptionReslover 处理异常解析类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
//resolveException 当控制器中任意一个方法出现异常,控制器没有自己的异常处理,则会进入当前方法
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView mv = new ModelAndView();
//针对不同类型的异常跳转到不同的页面
if (e instanceof UserNameNotFoundException) {
ModelAndView mv1 = new ModelAndView();
mv1.setViewName("login_error"); //login_error为登录出错页面
return mv1;
}
mv.setViewName("500"); //500为错误页面
return mv;
}
}1
2
3
4
5
6
7package yxnu.edu.exception;
//自定义的用户名找不到异常
public class UserNameNotFoundException extends RuntimeException {
public UserNameNotFoundException(String message) {
super(message);
}
}1
2
3
4
5
6
7
8@RequestMapping("/login")
public String login(String username,String pwd){
if ("admin".equals(username) && "123465".equals(pwd)){
return "index";
}else {
throw new UserNameNotFoundException("用户名不正确!!");
}
}前后端分离开发异常处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@ControllerAdvice //控制器中所有方法都会被通知
public class GlobalExceptionResolverRESTFUL {
//处理指定(指定的自定义)异常
@ExceptionHandler(value = UserNameNotFoundException.class)
@ResponseBody
public ResponseEntity<String> exceptionHandler1(Exception ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
//处理全局异常
@ExceptionHandler(value = Exception.class) //用在方法上,处理指定异常,value属性用来指定异常处理类型
@ResponseBody
public ResponseEntity<String> exceptionHandler2(Exception ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}1
2
3
4
5
6
7
8@GetMapping("/{username}/{pwd}")
public String login(@PathVariable("username")String username,@PathVariable("pwd")String pwd){
if ("admin".equals(username) && "123465".equals(pwd)){
return "index";
}else {
throw new UserNameNotFoundException("用户名不正确!!");
}
}
CORS跨域
CORS:全称”跨域资源共享”(Cross-origin resource sharing)
CORS需要浏览器和服务器同时支持,才可以实现跨域请求,目前几乎所有浏览器都支持CORS,IE则不能低于IE10。CORS的整个过程都由浏览器自动完成,前端无需做任何设置,跟平时发送ajax请求并无差异。所以,实现CORS的关键在于服务器,只要服务器实现CORS接口,就可以实现跨域通信。
什么是源:
1 |
|
哪些操作不会受到同源限制?
1 |
|
springboot中如何解决跨域问题?
局部解决
1
@CrossOrigin 用在类上,代表这个类中所有方法运行允许其他域中资源访问
全局解决
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15@Configuration
public class CrosConfig {
@Bean
public CorsFilter crosFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedHeader("*"); //允许任何头
configuration.addAllowedOrigin("*"); //允许任何域名
configuration.addAllowedMethod("*"); //允许任何方法
source.registerCorsConfiguration("/**",configuration); //处理所有请求的跨域
return new CorsFilter(source);
}
}
Jasypt加密
Jasypt 是一个 Java 库,它允许开发者以最小的努力为他/她的项目添加基本的加密功能,而且不需要对密码学的工作原理有深刻的了解。高安全性、基于标准的加密技术,既可用于单向加密也可用于双向加密。加密密码、文本、数字、二进制文件。
引入依赖
1
2
3
4
5
6<!--jasypt依赖-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>使用
1
2加密:类——root+秘钥(自定义的秘钥) 每一次运行都会生成一个新的加密结果,且每个结果都可用
解密:加密后的结果——类.方法 秘钥———得到结果1
2
3# 生产环境建议采用启动参数的形式传入
1、项目打成jar包部署时,启动命令也要加上 -Djasypt.encryptor.password=加密密钥
2、Junit测试方法的上启动参数也要加上 -Djasypt.encryptor.password=加密密钥1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#jasypt加密
# 测试环境可以采用在配置文件中配置
# 生产环境建议采用启动参数的形式传入
jasypt:
encryptor:
password: 121q5weqsaa #自定义的秘钥
#整合mybatis相关配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot?characterEncoding=UTF-8&serverTimezone=UTC
username: ENC(zpnOBQjHWSOlSBHiHfCohw==)
password: ENC(lXipkCbkAIhdVnRUt2dECw==)1
2
3
4
5
6
7
8
9
10
11@Autowired
StringEncryptor stringEncryptor;
@Test
public void test1() {
String secret = stringEncryptor.encrypt("root");
String decrypt = stringEncryptor.decrypt("zpnOBQjHWSOlSBHiHfCohw==");
System.out.println(secret);
System.out.println(decrypt);
}