SpringBoot-jar:内嵌tomcat
服务越来越多:springcloud
约定大于配置的核心思想,核心:自动装配,同时集成了大量第三方库配置。
优点:更快入门,开箱即用,内嵌容器简化web,没有冗余代码和很多xml配置
微服务:是一种架构风格,在开发一个应用的时候,这个应用必须构建成一系列小服务的组合,可以通过http和rpc的方式进行通信。把每个功能元素独立出来,把独立出来的功能元素动态组合,需要的功能元素采取组合。微服务架构是对功能元素进行赋值,而没有对整个应用进行复制。
1.直接在官网下载,导入idea
2.直接idea创建一个springboot项目
程序主入口
@SpringBootApplication public class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class, args); } }
此注解包含:
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
所有的spingboot依赖都是使用这个开头的spring-boot-starter
原理:
pom.xml:
1 .spring-boot-dependencies :父工程中,存放了核心依赖,统一进行了版本管理
2.自动配置了资源过滤
3.在写或者引入一些springBoot依赖的时候,不需要指定版本,因为有这些版本仓库
启动器:
4.启动器 :springboot的启动场景 sprign-boot-starter-web,就会帮我们自动导入web环境所有的依赖
5.会将所有的功能场景都会变成一个一个的启动器
6.我们要使用什么功能,就只需要找到对应的启动器就可以了 starter
主程序:
//标注这个类是一个SpringBoot的应用 启动类下所有的资源被注入 @SpringBootApplication public class HelloWorldApplication { public static void main(String[] args) { //将springboot应用类启动 反射 SpringApplication.run(HelloWorldApplication.class, args); } }
注解:
@SpringBootConfiguration @Configuration :Spring配置类 @Component :说明这也是一个spirng的组件 @EnableAutoConfiguration : 自动配置 @AutoConfigurationPackage :自动配置包 @Import({Registrar.class}) : 自动配置 `包注册` @Import({AutoConfigurationImportSelector.class}) //获取所有的配置 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."); return configurations; }
META-INF/spring.factories:自动配置的核心文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource); 所有的资源加载到配置类中
@ConditionalOnClass 在自动配置的类中有这个注解,会去判断条件,条件成立才会加载此类,这也是为什么自动配置了很多资源,但是依然需要加starter依赖,某些资源才能使用,而不是所有的类都加载进去
结论:所有自动配置都是在启动的时候,扫描并加载;spring.factories所有的自动配置类都在这里,但是不一定生效,要判断条件是否成立,只要导入了对应的starter,就有了对应的启动器了,有了启动器我们的自动装配就会生效,然后配置成功。
1.启动的时候,从类路径下/META-INF/spring.factories获取指定的值
2.将这些自动配置的类导入容器,自动配置就会生效,帮我们自动配置(类上也有@ConditionalOnClass)
3.以前我们需要配置的东西,springboot帮我们做了
4.整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.6.3.jar包下
5.它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
6.容器中也会存在多的***AutoConfiguration的文件,就是这些类给容器中导入了这个场景需要的所有组件,@Configuration,JavaConfig @Bean
7.免去了我们手动编写配置文件的工作
全面接管SpringMVC的配置
自定义配置的实现
#配置文件能写什么?---spring.factories 的联系 spring: mvc: format: date: dd/MM/yyyy dispatch-options-request: true #在配置文件中能配置的东西,一定会有 xxxAutoConfiguration 自动装配,默认值为 xxxProperties 文件 #可以和配置 文件绑定,所以我们就可以使用自定义的配置了 #打印日志,自动配置类已经启动并且已经生效的 和没匹配成功的 debug: true
-
SpringBoot启动会加载大量的自动配置类
-
我们需要的功能有没有在SpringBoot默认写好的自动配置类当中
-
我们再来看这个自动配置类中到底配置了哪些组件,存在则不需要手动配置
-
给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们只需要在配置文件中指定这些属性的值即可;
xxxAutoConfiguration:自动配置类,给容器中添加组件
xxxProperties:封装配置文件中的相关属性
springboot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(如果用户自己配置@bean),就用用户配置的(比如yml文件),如果没有就用自动配置的,如果有些组件可以存在多个,比如我们的mvc视图解析器,就将用户自定义的和默认的组合起来。
主启动类怎么运行? SpringApplication.run()
SpringApplication.run(HelloWorldApplication.class, args);
-
推断应用类型是否为WEB
-
加载所有可用初始化器
-
设置所有可用程序监听器
-
推断并设置main方法的定义类,找到运行的主类
配置文件 可修改SpringBoot自动配置的一些默认值
SpringBoot使用一个全局的配置文件,配置文件名称是固定的,如果两种同时存在,properties会后加载,覆盖yaml文件的内容
application.properties (官方不建议用)语法结构 key=value 层级结构不明显
application.yaml 语法结构 key:空格value 还能存对象 空格来控制层级
server: port: 8081 #对象 student: name: jack age: 3 #行内写法 students: {name: jack,age: 3} #数组 pets: - cat - dog #数组行内写法 pet: [cat,dog,pig]
可以给实体类赋值 一般用在配置类中,让一个类和一个文件绑定在一起;
也有松散绑定,yml中写last-name,这个和实体类的lastName是一样的,-后面跟着的字母默认是大写的,这就是松散绑定。
@ConfigurationProperties 将配置文件中配置的每一个属性的值,映射到这个组件中,告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定,参数prefix=" ",可以用于配置类中
@Value("旺财") private String name; @Value("3") private Integer age; @Component @ConfigurationProperties(prefix = "person") public class Person { private String name; private Integer age; private Boolean happy; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog;
person: name: jack age: ${random.uuid} happy: false birth: 2022/02/22 maps: {k1: v1,k2: v2} hello: lala lists: - cod - music - girl #springEL表达式的运用,随机占位 及 判断设定 #如果hello存在 就取person中hello的值+旺财 如果不存在就取hello+旺财 dog: name: ${person.hello:hello}旺财 age: 3
也可以自己写配置文件指定路径加载
//加载指定的配置文件 @PropertySource(value="calsspath:jack.properties") public class Person { //spring的EL表达式取出配置文件的值 @Value("${name}") private String name; private Integer age; private Boolean happy;
yaml 可以松散绑定
dog: first-name: tom age: 18
@ConfigurationProperties(prefix = "dog") public class Dog { private String firstName; private Integer age;
JSR303数据校验 @Validated
//数据校验 @Validated public class Person { @NotNull private String name; private String age;
配置文件的位置及优先级
多环境配置
server: port: 8080 #激活dev版本 spring: profiles: active: dev --- server: port: 8081 spring: profiles: dev --- server: port: 8082 spring: profiles: test
WEB项目
需要解决问题:
1.导入静态资源 2,首页 3.模板引擎Thymeleaf 4.装配扩展SpringMVC 5.具体业务 6.拦截器
7.国际化
静态资源导入
1.去webjars统一管理,导入依赖即可使用,通过8080/webjars/资源名 也可访问
2 在resources目录下可多再建public resources文件夹来存放静态资源,直接/1.html即可访问,resources目录下的优先级最高>static(默认)>public
一般public放公共资源,resources放一些文件,static静态资源。 如果再yml文件中自己配置了静态资源路径,则自带的静态资源路径会失效。只要在资源目录下index命名的首页文件,就能被访问。
首页的controller跳转
//在templates目录下的所有页面,只能通过controller来跳转! //这个需要模板引擎的支持!需要多导一个依赖 @Controller public class IndexController { @RequestMapping("/index") public String index(){ return "index"; } }
模板引擎thymleaf
作用:写一个页面模板,比如有些值是动态的,我们歇一歇表达式,组装一些数据,我们把这些数据找到,然后把这个模板和数据交给模板引擎,模板引擎会按照我们这个数据帮你把表达式解析,填充到我们指定的位置
导入依赖
<!--导入thymleaf依赖 我们都是基于3.x开发--> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</artifactId> </dependency>
肯定存在一个properties的相关的自动配置类
@ConfigurationProperties( prefix = "spring.thymeleaf" ) public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING; public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; private boolean checkTemplate = true; private boolean checkTemplateLocation = true; private String prefix = "classpath:/templates/"; private String suffix = ".html"; private String mode = "HTML"; private Charset encoding; private boolean cache;
@Controller public class HelloController { @GetMapping("/test") public String hello(Model model){ model.addAttribute("msg","<h2>helloThymeleaf</h2>"); return "test"; } }
可直接跳转到templates文件夹下的 test命名的html页面
需要在html中导入约束
<html xmlns:th="http://www.thymeleaf.org">
表达式
<span th:text="${today}">
-
Simple expressions:
//普通变量
-
Variable Expressions:
${...}
-
Selection Variable Expressions:
*{...}
//取国际化消息
-
Message Expressions:
#{...}
//取url
-
Link URL Expressions:
@{...}
//如果是一些片段表达式
-
Fragment Expressions:
~{...}
-
-
Literals(字面量)
//文本 单引号
-
Text literals:
'one text'
,'Another one!'
,…//数字直接写
-
Number literals:
0
,34
,3.0
,12.3
,…//boolean值
-
Boolean literals:
true
,false
//空
-
Null literal:
null
//标识符
-
Literal tokens:
one
,sometext
,main
,…
-
-
Text operations:(文本操作)
-
String concatenation:
+
-
Literal substitutions:
|The name is ${name}|
-
-
Arithmetic operations:(数学运算)
-
Binary operators:
+
,-
,*
,/
,%
-
Minus sign (unary operator):
-
-
-
Boolean operations:(布尔表达式)
-
Binary operators:
and
,or
-
Boolean negation (unary operator):
!
,not
(取反)
-
-
Comparisons and equality:(比较运算)
-
Comparators:
>
,<
,>=
,<=
(gt
,lt
,ge
,le
) -
Equality operators:
==
,!=
(eq
,ne
)
-
-
Conditional operators:(三元运算)
-
If-then:
(if) ? (then)
-
If-then-else:
(if) ? (then) : (else)
-
Default:
(value) ?: (defaultvalue)
-
-
Special tokens: 分割表达式
-
No-Operation:
_
-
基础语法
1 | Fragment inclusion | th:insert``th:replace |
---|---|---|
2 | Fragment iteration | th:each |
3 | Conditional evaluation | th:if``th:unless``th:switch``th:case |
4 | Local variable definition | th:object``th:with |
5 | General attribute modification | th:attr``th:attrprepend``th:attrappend |
6 | Specific attribute modification | th:value``th:href``th:src``... |
7 | Text (tag body modification) | th:text``th:utext |
8 | Fragment specification | th:fragment |
9 | Fragment removal | th:remove |
例子:
<body> <!--所有的html元素都可以被thymeleaf替换接管 th:元素--> <div th:text="${msg}"></div> <!--会将信息中的标签转译 不是纯文本信息了--> <div th:utext="${msg}"></div> </body> </html>
遍历:
@Controller public class HelloController { @GetMapping("/test") public String hello(Model model){ model.addAttribute("msg","<h2>helloThymeleaf</h2>"); //测试模板遍历,在集合中放两个元素 model.addAttribute("users", Arrays.asList("jack","tom")); return "test"; } }
<!--将users里面的内容遍历出来放在user里,文本显示出来 两种写法均可以--> <h3 th:each="user:${users}" th:text="${user}"></h3> <h3 th:each="user:${users}" >[[ ${user} ]]</h3>
扩展装配MVC
//写在config包下 //如果想定制化功能,重写这个组件,然后交给springboot 会自动装配 //通过这个类 扩展mvc 配置 要实现WebMvcConfigurer @Configuration public class MyMvcConfig implements WebMvcConfigurer { //ViewResolver 实现了视图解析器接口的类,就可以看做视图解析器 我们去接管视图解析器 重写他的方法resolveViewName @Bean public ViewResolver MyViewResolver() { return new MyViewResolver(); } //写静态内部类自定义一个视图解析器 public static class MyViewResolver implements ViewResolver { @Override public View resolveViewName(String viewName, Locale locale) throws Exception { return null; } } }
视图解析重写
//如果我们要扩展springmvc 官方建议我们这样去做 不能加@EnableWebMvc //@EnableWebMvc 导入了一个类 DelegatingWebMvcConfiguration:从容器中获取所有的webmvcconfig //会导致mvc自动配置崩盘 ,因为Condition判定 已经存在,不满足自动配置的条件 @Configuration public class MyMvcConfig implements WebMvcConfigurer { //扩展 视图跳转 @Override public void addViewControllers(ViewControllerRegistry registry) { //添加视图控制 这个路径可以直接跳转到test.html页面 registry.addViewController("/xie").setViewName("test"); } }
在springboot中,有非常多的xxxx Configuration帮助我们进行扩展配置,需要注意!
国际化
登录拦截器
@Controller public class LoginController { @RequestMapping("/login") public String login( @RequestParam("username")String username, @RequestParam("password")String password, Model model, HttpSession session){ //具体的业务 if(!StringUtils.isEmpty(username) && "123456".equals(password)){ session.setAttribute("loginUser",username); return "redirect:/main.html"; }else{ //告诉用户,你登录失败了 model.addAttribute("msg","用户名或密码错误!"); return "index"; } }
//登录拦截器 @Configuration public class LoginHandlercepter implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //登录成功之后应该有用户的session Object loginUser = request.getSession().getAttribute("loginUser"); //没有登录 if(loginUser==null){ request.setAttribute("msg","没有权限请先登录!"); request.getRequestDispatcher("/index.html").forward(request,response); return false; }else{ return true; } }
mvc的扩展配置里面需要将拦截器的拦截路径进行设定,排除不需要拦截的页面(比如一些静态资源)
导入druid依赖后配置
特点是日志监控,用了log4j,还需要导入log4j的依赖;可以自定义配置;防御sql注入
自定义配置,绑定配置文件
增加后台监控功能页面
某些请求过滤掉,不需要监控统计
整合Mybatis
整合包
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.1</version> </dependency>
spring.datasource.username=root spring.datasource.password=root spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
测试是否连接上
@SpringBootTest class MyBatisApplicationTests { @Autowired DataSource dataSource; @Test void contextLoads() throws SQLException { System.out.println(dataSource.getClass()); System.out.println(dataSource.getConnection()); } } //class com.zaxxer.hikari.HikariDataSource //HikariProxyConnection@1829313709 wrapping com.mysql.cj.jdbc.ConnectionImpl@7c663eaf
建实体类pojo,或者 entity
配置Mapper
//自动扫描包 @MapperScan("com.xie.mybatis.mapper") @SpringBootApplication //或者 //表示这是一个mybatis的mapper类 @Mapper public interface UserMapper { }
//被spring管理 也可以@Component @Repository @Mapper public interface UserMapper { }
可以将映射文件写在resources下面,通过properties/yml文件配置 进去
映射文件 sql语句
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xie.mybatis.mapper.UserMapper"> <select id="queryUserList" resultType="User" useCache="true"> select * from user </select> <select id="queryUserById" resultType="User"> select * from user where id = #{id} </select> <insert id="addUser" parameterType="User"> insert into user (id, name, pwd) values (#{id}, #{name}, #{pwd}) </insert> <update id="updateUser" parameterType="User"> update user set id=#{id}, name=#{name}, pwd=#{pwd} </update> <delete id="deleteUser" parameterType="int"> delete from user wehere id=#{id} </delete> </mapper>
省略业务层简单实现
RestController public class UserController { @Autowired private UserMapper mapper; @GetMapping("/queryAll") public List<User> queryAll(){ List<User> userList = mapper.queryUserList(); for (User user : userList) { System.out.println(user); } return userList; } //restful风格 @GetMapping("/queryId/{id}") public User queryId(@PathVariable int id){ User user1 = mapper.queryUserById(id); System.out.println(user1); return user1; } //@RequestBody 限定了前端传递的参数必须为json格式, //用POST方式进行提交,而且@RequestBody 只能有一个。 //@RequestParam()可以有多个,用于接收url中的key-value参数的传递。 // 通常我们用于get方式的请求 @GetMapping("/queryId2") public User queryId2(@RequestParam("userId") int id){ User user1 = mapper.queryUserById(id); System.out.println(user1); return user1; } }
SpringSecurity 主要目标是认证Authentication 授权 Authorization
导入web和thymleaf依赖 引入spring-boot-starter-security
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--导入thymleaf依赖 我们都是基于3.x开发--> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</artifactId> </dependency>
注意:
-
WebSecurityConfigurerAdapter 自定义Security策略 适配器模式
-
AuthenticationManagerBuilder 自定义认证策略 建造者模式
-
@EnableWebSecurity 开启WebSecurity模式 @Enable***开启某功能
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { //链式编程 授权 @Override protected void configure(HttpSecurity http) throws Exception { //首页所有人可以访问 功能页只有对应有权限的人才能访问 添加认证请求 ,所有的都能 //请求授权的规则 http.authorizeRequests().antMatchers("/").permitAll() //vip1 角色能访问 .antMatchers("/level1/**").hasRole("vip1") .antMatchers("/level2/**").hasRole("vip2") .antMatchers("/level4/**").hasRole("vip3"); //没有权限会默认到登录页面,需要开启登录的页面 http.formLogin(); } //认证,springboot 2.1.x可以直接使用 //密码编码 PasswordEncoder //新增了很多的加密方法 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //这里从内存 正常聪哥数据库读 auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("jack").password(new BCryptPasswordEncoder().encode("123456")) .roles("vip1","vip2").and() .withUser("root").password(new BCryptPasswordEncoder().encode("root")).roles("vip3").and() .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"); } }
通过数据库内容认证