SpringBoot
一、新建一个SpringBoot项目
通过上面步骤完成了基础项目的创建。就会自动生成以下文件(可以删除无用文件)。
1、程序的主启动类
2、一个 application.properties 配置文件
3、一个 测试类
4、一个 pom.xml
补全我们需要的包:
二、第一个程序:Hello,SpringBoot我们先尝试写一个请求运行一下看结果。
在controller包中创建HelloController类并编写业务代码
package cn.tuan.springbootstudy.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String helloWorld() {
return "hello,world";
}
}
运行访问http://localhost:8080/hello得到结果,我们输出了helloworld!
三、yaml语法yaml是spring官方推荐的配置文件使用的语法,我们可以新建一个application.yaml文件替代application.properties文件
配置文件优先级:properties>yaml>yml
1.yaml语法如下:#正常的key-value键值对
server:
port: 8081
#存放对象(注意空格,yaml对缩进敏感)
student:
name: tuanzi
age: 19
#对象行内写法
student2: {name: tuanzi, age: 19}
#存放数组
arr: [19, 21,36]
#多行数组
pets:
- dog
- cat
- pig
可以看到yaml可以存放多种数据而properties只能存放kv键值对。
yaml的强大之处在于:yaml可以注入到我们的配置类中
2.yaml给属性赋值
- 首先编写一个测试实体类Person
package cn.tuan.springbootstudy.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component//注册到bean中
@ConfigurationProperties(prefix = "person")//这个注解就是在匹配配置文件中的属性从而实现赋值
public class Person {
private String name;
private Integer age;
private boolean happy;
private Date birth;
private Map maps;
private List
- 接下来我们编写application.yaml中的内容,其中的属性要与Person类对应
person:
name: tuanzi
age: 7
happy: true
#Date的格式不能错
birth: 2014/11/02
#kv键值对冒号之后也要加上空格
maps: {k1: v1,k2: v2}
lists:
- code
- music
- girl
dog:
name: 旺财
age: 3
所以给属性赋值的关键就是**@ConfigurationProperties()**这个注解,这个注解有一个参数prefix代表配置文件中属性的键值。如果键值里的类型与实体类中的属性springboot将无法正常启动,但不必给每一个属性都赋值,没有赋值的属性为null,也可以给不存在的属性赋值(一般没有什么意义,会被忽视)。
建议:如果我们业务中只需要为某个属性赋值,直接在该属性上用@Value()注解实现即可
如果我们专门编写了一个JavaBean来和配置文件进行映射,直接使用@configurationProperties
3.JSR303数据校验当我们有些属性想要赋予固定格式的值时就要使用JSR303数据校验,它可以帮你判断所赋予属性的值格式是否正确
使用jsr303数据校验首先导入validation启动器依赖
org.springframework.boot spring-boot-starter-validation
然后我们在实体类中就可以使用@validata注释开启数据校验,再在属性上使用对应注解规定格式
package cn.tuan.springbootstudy.pojo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.Email;
@Component
@ConfigurationProperties(prefix = "person")
@Validated //开启数据校验
public class Person {
@Email//标记该属性必须为邮箱格式
private String userName;
}
此时userName属性必须为邮箱格式,否则会报错。
格式注解有以下这些:
| @Null | 必须为null |
|---|---|
| @NotNull | 必须不为null |
| @AssertTrue | 必须为true |
| @AssertFasle | 必须为false |
| @Min(value)/@DecimalMin(value) | 必须为数字且必须大于等于指定的最小值 |
| @Max(value)/@DecimalMax(value) | 必须为数字且必须小于等于指定的最大值 |
| @Size(max,min) | 被注解元素必须在指定范围内 |
| @Digits(integer,fraction) | 必须为数字且其值必须在可接受范围内 |
| @Past | 必须是一个过去的日期 |
| @Future | 必须是一个将来的日期 |
| @Pattern(value) | 必须符合指定的正则表达式 |
| 必须是电子邮箱地址 | |
| @Length | 被注释的字符串大小必须在指定范围内 |
| @NotEmpty | 字符串必须非空 |
| @Range | 被注释的元素必须在合适的范围内 |
①多配置文件指定激活(配置内容多的话推荐使用)
springboot生产中可能针对不同的环境需要使用不同的配置文件,这里就可以使用多环境配置,我们写多个配置文件然后可以选择激活哪一个配置文件。
首先建立配置文件时文件名都应该为application-xxx.yaml
然后再application.yaml中选择使用的配置文件
spring:
profiles:
active: test #此处值为配置文件名-后面的内容
这时激活的就是application.test.yaml配置文件。
②一个配置文件(小工程配置内容少推荐使用)
yaml支持多文档分割,通过—分割配置文件
server:
port: 8080
spring:
profiles:
active: dev
---
server:
port: 8081
spring:
profiles: dev
---
server:
port: 8082
spring:
profiles: test
这样一个yaml就相当于三个配置文件,此时使用的是dev开启的8081端口
2.自动装配原理①springboot在启动的时候会加载大量的自动配置类
②我们要看我们的功能有没有在springboot默认写好的自动配置类当中
③我们再看这个自动配置类中到底配置了哪些组件(我们要用的组件存在其中就不需要再手动配置了)
④给容器中自动配置类添加组件的时候会从properties类中获取某些属性,我们只需要在配置文件中指定这些属性的值即可
xxxAutoConfiguration:自动配置类,给容器中添加组件
xxxProperties:封装配置文件中相关属性
五、Web开发 1.静态资源处理
在springboot中我们使用以下方法处理静态资源:
webjars库中导入的静态资源不会被过滤 通过**localhost:8080/webjars/***访问到
resources目录下有三个目录中的静态资源不会被过滤(按优先级排序):resources,static(默认),public
通过**localhost:8080/***直接访问到
2.首页定制首页定制
只需要在静态资源中建立一个index.html 这个页面就是定制的首页,默认访问进入的就是这个页面但我们一般不会直接进入首页,而是通过一个controller请求跳转到首页,这个时候我们就要把index.html放在resources下的templates目录下,templates目录中的所有页面只能通过controller来跳转且需要模板引擎的支持(thymeleaf)。 3.thymeleaf模板引擎
首先导入thymeleaf依赖
org.springframework.boot spring-boot-starter-thymeleaf
所有的html页面放在templates目录下并添加命名空间就可以thymeleaf模板了。
命名空间:
thymeleaf语法:
简单表达式:取普通变量**${…}** 国际化的消息**#{…}** URL**@{…}** 片段表达式**~{}**
六、整合Mybistis- 首先导入mybatis-springboot依赖
org.mybatis.spring.boot mybatis-spring-boot-starter 2.2.1
在application.properties或者application.yaml中配置mybatis
spring.datasource.username=root spring.datasource.password=123456 spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #整合mybatis mybatis.type-aliases-package=com.tuan.pojo mybayis.mapper-locations=classpath:mybatis/mapper/*.xml
创建数据库对应pojo包下实体类
package com.tuan.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
创建mapper层对应的UserMapper接口
package com.tuan.mapper;
import com.tuan.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface UserMapper {
List queryUserList();
User queryUserById(int id);
int updateUser(User user);
int deleteUser(int id);
}
在resources目录下创建mabatis目录,再在mybatis目录下创建mapper目录(和application中的mybayis.mapper-locations对应) ,在该目录下创建Mapper接口对应的xml
编写对应的controller层代码
package com.tuan.controller;
import com.tuan.mapper.UserMapper;
import com.tuan.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/queryUserList")
public List queryUserList(){
List users = userMapper.queryUserList();
return users;
}
@GetMapping("queryById")
public User queryUser() {
return userMapper.queryUserById(1);
}
}
启动访问对应页面即可。
- 导入依赖
org.springframework.boot spring-boot-starter-security
- 在config包下编写一个继承WebSecurityConfigurerAdapter的类并重写其中的方法实现各种权限控制
- 从内存中读取用户
package com.tuan.config;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有对应有权限的人才能访问
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/levle1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//设置没有权限默认会到登录界面(默认转发到/login请求) //自定义登录页面挑战请求(现在跳转至tologin请求)
http.formLogin(); http.formLogin().loginPage("/tologin");
//开启注销功能(默认转发到/logout请求) //或者指定注销成功后的跳转页面
http.logout(); http.logout().logoutSuccessUrl("/");
//开启记住我功能(保存cookie两周)(参数是页面中的一个多选框的name)
http.rememberMe().rememberMeParameter("remrember");
}
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常应该从数据库读取,这里是从内存中读取的。
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and().withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and().withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}
- 从数据库中读取用户
package com.tuan.config;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//认证
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
UserBuilder users = User.withDefaultPasswordEncoder();
auth.jdbcAuthentication().dataSource(dataSource)
.withDefaultSchema()
.withUser(users.username("user").password("password").roles("vip1"))
.withUser(users.username("admin").password("password").roles("vip1","vip2","vip3"));
}
}
八、Swagger
新建springboot-web项目
导入相关依赖
io.springfox
springfox-boot-starter
3.0.0
编写一个hello工程测试
配置SwaggerConfig
package com.tuan.config;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableOpenApi
public class SwaggerConfig {}
启动项目访问http://localhost:8080/swagger-ui/即可使用
Swagger的bean实例Docket
package com.tuan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.documentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
@Configuration
@EnableOpenApi
public class SwaggerConfig {
//配置Swagger的Docket的bean实例
@Bean
public Docket docket() {
return new Docket(documentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
//配置apiInfo
private ApiInfo apiInfo(){
Contact contact = new Contact("tuan", "http://localhost:8080/hello", "981444877@qq.com");
return new ApiInfo(
"团的SwaggerApi文档",
"hhh",
"v1.0",
"http://localhost:8080/hello",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList()
);
}
}
配置过后再打开页面就可以看到信息已经变换了。
Swagger配置扫描接口Docket.select()
//配置Swagger的Docket的bean实例
public Docket docket() {
return new Docket(documentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.enable(true) //是否开启swagger,默认为true可以不用配置
.apis(RequestHandlerSelectors.basePackage("com.tuan.controller"))//在这里指定要扫描的包
//2 .apis(RequestHandlerSelectors.any()) //扫描全部的包
//3 .apis(RequestHandlerSelectors.none()) //都不扫描
//4 .apis(RequestHandlerSelectors.withClassAnnotation(GetMapping.class)) //扫描类上的注解,参数为注解的反射对象
//5 .apis(RequestHandlerSelectors.withMethodAnnotation(RestController.class)) //扫描方法上的注解,参数为注解的反射对象
.paths(PathSelectors.ant("/tuan/**")) //过滤给定参数中的请求(url)路径
.build();
}
如何实现在生产环境中使用Swagger而在发布时禁用Swagger?
@Bean
public Docket docket(Environment environment) {
//设置要显示的Swagger环境
Profiles profiles = Profiles.of("dev","test");
//判断项目的环境是否符合
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(documentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(flag) //在这里判断是否开启Swagger
.select()
.apis(RequestHandlerSelectors.any()) //扫描全部的包
.build();
}
配置Swagger分组
return new Docket(documentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("tuan")
.select()
.apis(RequestHandlerSelectors.any()) //扫描全部的包
.build();
如何配置多个组
@Bean
public Docket docket1() {
return new Docket(documentationType.SWAGGER_2).groupName("A");
}
@Bean
public Docket docket2() {
return new Docket(documentationType.SWAGGER_2).groupName("B");
}
@Bean
public Docket docket3() {
return new Docket(documentationType.SWAGGER_2).groupName("C");
}
Swagger中的常用注释
实体类必须要在controller返回了才会显示到文档中
实体类中的private属性必须要有getter/setter方法才会出现在文档中
package com.tuan.pojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
//类上的文档注释
@ApiModel("用户实体类")
public class User {
//属性上的文档注释
@ApiModelProperty("用户名")
private String name;
@ApiModelProperty("密码")
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.tuan.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api("hello控制类")
@RestController
public class HelloController {
@ApiOperation("hello控制方法")
@RequestMapping(value = "/hello")
public String hello(@ApiParam("用户名") String name){
return "Hello,World";
}
}
总结:
@ApiModel(“用户实体类”) 实体类上的文档注释
@ApiModelProperty(“用户名”) 实体类属性上的文档注释
@Api(“hello控制类”) controller类上的注释
@ApiOperation(“hello控制方法”) controller类中方法上的注释
@ApiParam(“用户名”) controller类中方法参数上的注释
九、异步任务我们只需要告诉开启springboot的异步注解功能并告诉它这个任务异步任务即可实现异步加载
在springboot的启动类上添加一个@EnableAsync 注解开启异步注解功能
然后在异步方法上添加@Async 注解
如此前台便会先加载出来页面 后台去处理数据,而不必等到后台数据处理完毕之后再加载页面,提高用户体验
十、邮件任务- 首先导入启动器依赖
org.springframework.boot spring-boot-starter-mail
编写配置
spring.mail.username=981444877@qq.com spring.mail.password=wceqlxtndhglbccf spring.mail.host=smtp.qq.com # qq邮箱需开启加密授权验证 spring.mail.properties.mail.smtp.ssl.enable=true
编写java业务逻辑代码发送简单邮件
//自动注入邮件发送
@Autowired
JavaMailSenderImpl mailSender;
@Test
void contextLoads() {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject("测试发送"); //设置邮件标题
mailMessage.setText("test"); //设置邮件内容
mailMessage.setTo("981444877@qq.com"); //设置邮件收信人
mailMessage.setFrom("981444877@qq.com"); //设置邮件发送人
mailSender.send(mailMessage);
}
复杂邮件发送
@Test
void contextLoads() throws MessagingException {
//创建一个复杂邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
//使用MimeMessageHelper类组装复杂邮件
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
//正文
helper.setSubject("邮件测试~~");
helper.setText("Mail Test
",true);
//附件
//helper.addAttachment("1.jpg",new File(""));
helper.setTo("981444877@qq.com");
helper.setFrom("981444877@qq.com");
mailSender.send(mimeMessage);
}
启动类上添加注解**@EnableScheduling** 开启任务调度支持
Service层的方法添加**@Scheduled(cron = )** 注解表示该方法将在特定的时间被执行,参数为cron表达式
package com.tuan.Service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class ScheduledService {
//在一个特定的时间执行这个代码
// 秒 分 时 日 月 星期 年
@Scheduled(cron = "0 * * * * 0-7 *")
public void hello() {
System.out.println("hello");
}
}



