1 springboot概述 1.1 概述 Spring Boot是Spring提供的一个子项目,用于快速构建Spring应用程序。
1.2 传统方式构建spring应用程序 1 导入依赖繁琐。 2 项目配置繁琐。
1.3 SpringBoot特性 1.3.1 起步依赖 本质上就是一个Maven坐标,整合了完成一个功能需要的所有坐标。(解决配置繁琐的问题)
1.3.2 自动配置 遵循约定大于配置的原则,在boot程序启动后,一些bean对象会自动注入到iloc容器,不需要手动声明,简化开发。(解决项目配置繁琐的问题)
1.3.3 其他特性 1 内嵌的Tomcat、Jetty(无需部署WAR文件)。 2 外部化配置。部署完毕后,需要修改,只需要修改项目外部配置文件,直接重新启动项目就可以。 3 不需要XML配置(properties/yml)。
2 sprintboot入门 需求:使用SpringBoot开发一个web应用,浏览器发起请求/hello后,给浏览器返回字符串”hello world~”。
1 创建Maven工程。 2 导入spring-boot-starter-web起步依赖。 3 编写Controller。
1 2 3 4 5 6 7 @RestController public class HelloController { @RequestMapping ("/hello" ) public String hello () { return "Hello World~" ; } }
4 提供启动类。
1 2 3 4 5 6 7 @SpringBootApplication public class SpringbootSyqApplication { public static void main (String[] args) { SpringApplication.run(SpringbootSyqApplication.class , args ) ; } }
3 sprintboot工程创建 手动创建SpringBoot工程 1 创建Maven工程。 2 引入依赖。 3 提供启动类。
4 springboot配置文件_基本使用 4.1 学习路径 4.1.1 基础篇 配置文件。 整合MyBatis。 Bean管理。 自动配置管理。 自定义starter。
4.1.2 实战篇 项目开发。 整合三方技术。 项目部署。
4.1.3 面试篇 面试题。 源码。
4.2 配置文件 1 properties配置文件。application.properties文件。
1 2 3 4 server.port=9090 server.servlet.context-path=/start
2 yaml配置文件(实际开发中更常用)。application.yml(主要)/application.yaml。
5 yml配置信息书写和获取 5.1 三方技术配置信息 只需编写配置信息,起步依赖会自动获取配置信息。
5.2 自定义配置信息 不仅需要编写配置信息,还需要实现配置信息的获取代码。
5.3 yml配置信息书写 1 值前边必须有空格,作为分隔符。 2 使用空格作为缩进表示层级关系,相同的层级左侧对齐。
1 2 3 4 5 hobbies: - 打篮球 - 打豆豆 - 打游戏
5.4 配置信息的获取 5.4.1 @Value 1 2 3 4 5 6 @Value ("${键名}" )@Value ("${email.user}" )public String user;
在使用@Value注解时,多个层级的键名使用.来连接。
5.4.2 ConfigurationProperties(prefix=”前缀”) 实体类的成员变量名与配置文件中的键名一致。
1 @ConfigurationProperties (prefix="email" )
6 springboot整合mybatis 1 引入mybatis-spring-boot-starter依赖。pom.xml文件修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 3.0.3</version > </dependency > <dependency > <groupId > com.mysql</groupId > <artifactId > mysql-connector-j</artifactId > </dependency >
2 yml文件数据库配置。数据库驱动,数据库链接,用户名,密码等。SpringBoot自动读取配置信息。
1 2 3 4 5 6 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/kongming username: root password: 181234
目标:查询User表指定id的数据,响应给浏览器。 Mapper编写:
1 2 3 4 5 6 @Mapper public interface UserMapper { @Select ("select * from user where id = #{id}" ) public User findById (Integer id) ; }
Service编写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public interface UserService { public User findById (Integer id) ; } @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User findById (Integer id) { return userMapper.findById(id); } }
Controller编写:
1 2 3 4 5 6 7 8 9 10 @RestController public class UserController { @Autowired private UserService userService; @RequestMapping ("/findById" ) public User findById (Integer id) { return userService.findById(id); } }
7 Bean扫描 标签:
1 <context:component-scan base-package ="com.kongming" >
注解:
1 @ComponentScan (basePackages="com.kongming" )
在SpringBoot启动类的注解,实际上是一个组合注解:
1 2 3 4 5 6 7 8 9 @SpringBootApplication @ComponentScan (basePackages="com.kongming" )@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
8 Bean注册 如果要注册的Bean对象来自于第三方(不是自定义的),是无法用@Component及衍生注解声明bean的。Spring提供了两个注解来解决问题: 1 @Bean 2 @Import
1 mvn install:install-file -Dfile=C:\SunYuQi\data\研一\工作\springboot资料\02_资料\02_Bean注册资料\common-pojo-1.0-SNAPSHOT.jar -DgroupId=cn.itcast -DartifactId=common-pojo -Dversion=1.0 -Dpackaging=jar
1 2 3 4 5 6 <!--第三方包导入--> <dependency> <groupId>cn.itcast</groupId> <artifactId>common-pojo</artifactId> <version>1.0</version> </dependency>
8.1 @Bean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Configuration @SpringBootApplication public class SpringbootSyqApplication { public static void main (String[] args) { ApplicationContext context = SpringApplication.run(SpringbootSyqApplication.class , args ) ; Country country = context.getBean(Country.class ) ; System.out.println(country); } @Bean public Country country () { return new Country(); } }
建议的写法:
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 @Configuration public class CommonConfig { @Bean public Country country () { return new Country(); } @Bean public Province province () { return new Province(); } @Bean ("aa" ) @Bean () public Province province () { System.out.println("province" +country()); return new Province(); } } ```java @SpringBootApplication public class SpringbootSyqApplication { public static void main (String[] args) { ApplicationContext context = SpringApplication.run(SpringbootSyqApplication.class , args ) ; Country country = context.getBean(Country.class ) ; System.out.println(country); System.out.println(context.getBean("province" )); } }
8.2 @Import 使用@Import相当于手动扫描类。 1 导入配置类。 2 导入ImportSelector接口实现类。
1 2 3 4 5 6 7 8 9 10 11 12 13 @SpringBootApplication @Import (CommonConfig.class ) public class SpringbootSyqApplication { public static void main (String[] args) { ApplicationContext context = SpringApplication.run(SpringbootSyqApplication.class , args ) ; Country country = context.getBean(Country.class ) ; System.out.println(country); System.out.println(context.getBean("province" )); } }
1 2 3 4 5 6 7 8 9 10 @Import (CommonImportSelector.class ) public class CommonImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"config.CommonConfig" }; } }
在配置文件中,每行一个类名。实现上述代码的注释部分,完整如下:
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 public class CommonImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { List<String> imports = new ArrayList<String>(); InputStream is = CommonImportSelector.class.getClassLoader().getResourceAsStream("common.imports"); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = null ; try { while ((line = br.readLine())!=null ){ imports.add(line); } } catch (IOException e) { throw new RuntimeException(e); } finally { if (br!=null ){ try { br.close(); } catch (IOException e) { throw new RuntimeException(e); } } } return imports.toArray(new String[0 ]); } }
1 2 3 4 5 6 7 8 9 10 @Target (ElementType.TYPE)@Retention (RetentionPolicy.RUNTIME)@Import (CommonImportSelector.class ) public @interface EnableCommonConfig {} @EnableCommonConfig
9 注册条件 9.1 需要注册条件的原因 配置文件中配置:
1 2 3 country: name: china system: socialism
在java文件中读取配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Configuration public class CommonConfig { @Bean public Country country (@Value("${country.name}" ) String name, @Value ("${country.system}" ) String system) { Country country = new Country(); country.setName(name); country.setSystem(system); return country; } @Bean () public Province province (Country country) { System.out.println("province" +country); return new Province(); } }
我们希望达到的效果是,如果配置文件中配置了指定的信息,则注入,否则不注入。
9.2 注册条件 SpringBoot提供了设置注册生效条件的注解@Conditional.
1 2 3 4 5 6 7 8 9 10 @ConditionalOnProperty (prefix = "country" ,name = {"name" ,"system" })@Bean public Country country (@Value("${country.name}" ) String name, @Value ("${country.system}" ) String system) { Country country = new Country(); country.setName(name); country.setSystem(system); return country; }
1 2 3 4 5 6 @Bean ()@ConditionalOnMissingBean (Country.class ) public Province province () { return new Province(); }
1 2 3 4 5 6 7 @Bean ()@ConditionalOnClass (name="org.springframework.web.servlet.DispatcherServlet" )public Province province () { return new Province(); }
10 自动配置原理 10.1 需要学习自动配置原理的原因 1 自定义starter。 2 面试。
10.2 自动配置体验 遵循约定大于配置的原则,在boot程序启动后,起步依赖中的一些bean对象会自动注入到ioc容器。程序引入spring-boot-starter-web起步依赖,启动后,会自动往ioc容器中注入DispatcherServlet。
1 mvn install:install-file -Dfile=C:\SunYuQi\data\研一\工作\springboot资料\02_资料\03_自动配置\common-pojo-2.0-SNAPSHOT.jar -DgroupId=cn.itcast -DartifactId=common-pojo -Dversion=2.0 -Dpackaging=jar
10.3 自动配置原理 在主启动类上添加了SpringBootApplication注解,这个注解组合了EnableAutoConfiguration注解。 EnableAutoConfiguration注解又组合了Import注解,导入了AutoConfigurationImportSelector类。 实现selectImports方法,这个方法经过层层调用,最终会读取META-INF目录下的后缀名为imports的文件,当然了,boot2.7以前的版本,读取的是spring.factories文件。 读取到全类名之后,会解析注册条件,也就是@Conditional及其衍生注解,把满足注册条件的Bean对象自动注入到IOC容器中。
11 自定义starter 11.1 场景 在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将公共组件封装为SpringBoot的starter。 xxxx-autoconfigure <—自动配置功能 xxxx-starter <—依赖管理功能
11.2 自定义mybatis的starter 1 创建dmybatis-spring-boot-autoconfigure模块,提供自动配置功能,并自定义配置文件 META/INF/spring/xxx.imports. 2 创建dmybatis-spring-boot-stater模块,在starter中引入自动配置模块。
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 @AutoConfiguration public class MybatisAutoConfig { @Bean public SqlSessionFactoryBean sqlSessionFactoryBean (DataSource dataSource) { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); return sqlSessionFactoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer (BeanFactory beanFactory) { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); List<String> packages = AutoConfigurationPackages.get(beanFactory); String p = packages.get(0 ); mapperScannerConfigurer.setBasePackage(p); mapperScannerConfigurer.setAnnotationClass(Mapper.class ) ; return mapperScannerConfigurer; } }
1 com.kongming.config.MybatisAutoConfig
pom文件中是定义好的autoconfig和autoconfig的依赖。
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 <!--引入定义好的autoconfig--> <dependency> <groupId>com.kongming</groupId> <artifactId>dmybatis-spring-boot-autoconfigure</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>3.3.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <version>3.3.1</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.14</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <dependency>
12 实战篇-开发模式和环境搭建 12.1 实战开发的技术栈 后台: Validation做参数校验。 Mybatis做数据库操作。 Redis做缓存。 Junit做单元测试。 SpringBoot项目部署。 前端: Vite Vue项目的脚手架。 Router路由。 Pina状态管理。 Element-Plus UI组件。
12.2 开发模式 接口文档: 1 路径和请求方式。 2 请求参数。 3 响应数据。
12.3 环境搭建 执行资料中的big_event.sql脚本,准备数据库表。 创建springboot工程,引入对应的依赖(web,mybatis,mysql驱动)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 3.0.3</version > </dependency > <dependency > <groupId > com.mysql</groupId > <artifactId > mysql-connector-j</artifactId > </dependency >
配置文件application.yml中引入mybatis的配置信息。
1 2 3 4 5 6 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/kongming username: root password: 181234
创建包结构,并准备实体类。 其中pojo存放实体类,utils存放工具类。
13 实战篇-注册接口 用户模块需要开发的接口: 1 注册。 2 登录。 3 获取用户详细信息。 4 更新用户基本信息。 5 更新用户头像。 6 更新用户密码。
lowbok:在编译阶段为实体类自动生成setter,getter,toString方法 使用lowbok: (1)在pom文件中引入依赖; (2)在实体类上添加注解。
1 2 3 4 <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > </dependency >
1 2 3 4 5 6 7 8 9 10 11 @Data public class User { private Integer id; private String username; private String password; private String nickname; private String email; private String userPic; private LocalDateTime createTime; private LocalDateTime updateTime; }
在其余实体类中都添加Data注解。在缺少构造方法的实体类中添加下列注解:
1 2 3 4 @NoArgsConstructor @AllArgsConstructor
13.1 注册 明确需求->阅读接口文档->思路分析->开发->测试。
13.1.1 基本信息 请求路径:/user/register 请求方式:POST 接口描述:该接口用于注册新用户
13.1.2 请求参数 请求参数格式:x-www-form-urlencoded
请求参数说明:
参数名称
说明
类型
是否必须
备注
username
用户名
string
是
5~16位非空字符
password
密码
string
是
5~16位非空字符
请求数据样例:
1 username=zhangsan&password=123456
13.1.3 响应数据 响应数据类型:application/json
响应参数说明:
名称
类型
是否必须
默认值
备注
其他信息
code
number
必须
响应码, 0-成功,1-失败
message
string
非必须
提示信息
data
object
非必须
返回的数据
响应数据样例:
1 2 3 4 5 { "code" : 0 , "message" : "操作成功" , "data" : null }
13.2 代码编写 1 Controller部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @RestController @RequestMapping ("/user" )public class UserController { @Autowired private UserService userService; @PostMapping ("/register" ) public Result register (String username, String password) { User u = userService.findByUserName(username); if (u == null ){ userService.register(username,password); return Result.success(); }else { return Result.error("用户名已被占用" ); } } }
2 Service部分。
1 2 3 4 5 6 7 8 9 public interface UserService { User findByUserName (String username) ; void register (String username, String password) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User findByUserName (String username) { User u = userMapper.findByUserName(username); return u; } @Override public void register (String username, String password) { String md5String = Md5Util.getMD5String(password); userMapper.add(username,md5String); } }
3 Mapper部分。
1 2 3 4 5 6 7 8 9 10 @Mapper public interface UserMapper { @Select ("select * from user where username=#{username}" ) User findByUserName (String username) ; @Insert ("insert into user(username,password,create_time,update_time)" + "values (#{username},#{password},now(),now())" ) void add (String username, String password) ; }
14 实战篇-注册接口参数校验 在接口文档中,请求参数必须是5-16位的非空字符。后端必须保证前端传来的参数是符合要求的。
14.1 手动添加校验 在controller层添加校验。
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 @RestController @RequestMapping ("/user" )public class UserController { @Autowired private UserService userService; @PostMapping ("/register" ) public Result register (String username, String password) { if (username != null && username.length()>=5 && username.length()<=16 && password != null && password.length()>=5 && password.length()<=16 ) { User u = userService.findByUserName(username); if (u == null ){ userService.register(username,password); return Result.success(); }else { return Result.error("用户名已被占用" ); } }else { return Result.error("参数不合法" ); } } }
14.2 Spring Validation 上述参数校验代码过于繁琐,Spring提供一个参数校验框架,使用预定义的注解完成参数校验。 1 引入Spring Validation起步依赖。
1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-validation</artifactId > </dependency >
2 在参数前面添加@Pattern注解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @RestController @RequestMapping ("/user" )@Validated public class UserController { @Autowired private UserService userService; @PostMapping ("/register" ) public Result register (@Pattern(regexp = "^\\S{5,16}$" ) String username, @Pattern (regexp = "^\\S{5,16}$" ) String password) { User u = userService.findByUserName(username); if (u == null ){ userService.register(username,password); return Result.success(); }else { return Result.error("用户名已被占用" ); } } }
3 在Controller类上添加@Validation注解。
4 在全局异常处理器中处理参数校验失败的异常。参数校验失败异常处理。@Restxxxb表示所有返回值都会被自动转化为json字符串。
1 2 3 4 5 6 7 8 @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler (Exception.class ) public Result handleException (Exception e ) { e.printStackTrace(); return Result.error(StringUtils.hasLength(e.getMessage())?e.getMessage():"操作失败" ); } }
15 实战篇-登录主逻辑 15.1 基本信息
请求路径:/user/login 请求方式:POST 接口描述:该接口用于登录
15.2 请求参数 请求参数格式:x-www-form-urlencoded
请求参数说明:
参数名称
说明
类型
是否必须
备注
username
用户名
string
是
5~16位非空字符
password
密码
string
是
5~16位非空字符
请求数据样例:
1 username=zhangsan&password=123456
15.3 响应数据 响应数据类型:application/json
响应参数说明:
名称
类型
是否必须
默认值
备注
其他信息
code
number
必须
响应码, 0-成功,1-失败
message
string
非必须
提示信息
data
string
必须
返回的数据,jwt令牌
响应数据样例:
1 2 3 4 5 { "code" : 0 , "message" : "操作成功" , "data" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOnsiaWQiOjUsInVzZXJuYW1lIjoid2FuZ2JhIn0sImV4cCI6MTY5MzcxNTk3OH0.pE_RATcoF7Nm9KEp9eC3CzcBbKWAFOL0IsuMNjnZ95M" }
jwt令牌是一串字符串。
15.4 备注说明
用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,浏览器都需要在请求头header中携带到服务端,请求头的名称为 Authorization,值为登录时下发的JWT令牌。 如果检测到用户未登录,则http响应状态码为401
15.5 代码实现 service和mapper使用用户注册中写好的即可。主要需要在controller中添加用户登录模块代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @PostMapping ("/login" )public Result<String> login (@Pattern(regexp = "^\\S{5,16}$" ) String username, @Pattern (regexp = "^\\S{5,16}$" ) String password) { User loginUser = userService.findByUserName(username); if (loginUser == null ){ return Result.error("用户名错误" ); } if (Md5Util.getMD5String(password).equals(loginUser.getPassword())){ return Result.success("jwt token令牌.." ); } return Result.error("密码错误" ); }
16 实战篇-登录认证引入 登录认证-在未登录的情况下,可以访问到其他资源。
17 实战篇-JWT令牌 18 实战篇-登录认证-完成 19 实战篇-获取用户详细信息 20 实战篇-获取用户详细信息-Thread 21 实战篇-更新用户基本信息