话不多说,先上学习网址:blog.csdn.net/qq_41978509…
1、第一个springboot程序
这个简单不多说,介绍个修改启动界面的 ASCII码 网址:www.bootschool.net/ascii 把这个banner.txt放置在配置文件同一目录下即可
2、自动配置原理探索 - @SpringBootApplication
关于springboot,谈谈你的理解:
- springboot的自动装配
- run(): ①判断当前项目是普通项目还是web项目 ②推断并设置main方法的定义类,找到运行的主类 ③run方法里面有一些监听器,这些监听器是全局存在的,它的作用是获取上下文处理一些bean,所有的bean无论是加载还是生产初始化多存在。
3、springboot配置文件
3.1 配置文件
yaml基础语法 说明:语法要求严格!
1、空格不能省略
2、以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。
3、属性和值的大小写都是十分敏感的。
#对象、Map格式
key:
value1:
value2:
student:
name: qinjiang
age: 3
#行内写法
student: {name: qinjiang,age: 3}
#数组List、Set
pets:
- cat
- dog
- pig
#行内写法
pets: [cat,dog,pig]
3.2 给实体对象赋值
@Component //注册bean到容器中,使得这个类可以被扫描到
public class Dog {
@Value("阿黄")
private String name;
@Value("18")
private Integer age;
}
通过yaml文件赋值
编写一个yaml配置!
person:
name: qinjiang
age: 3
happy: false
birth: 2000/01/01
maps: {k1: v1,k2: v2}
lists:
- code
- girl
- music
dog:
name: 旺财
age: 1
ConfigurationProperties(prefix = "person")注入到类中
/*
@ConfigurationProperties作用:
将配置文件中配置的每一个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@Component //注册bean
@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;
}
加载指定的配置文件
@PropertySource(value = "classpath:person.properties")
@Component //注册bean
public class Person {
@Value("${name}")//有点像jsp了哦,EL表达式
private String name;
......
}
配置文件占位符
person:
name: qinjiang${random.uuid} # 随机uuid
age: ${random.int} # 随机int
happy: false
birth: 2000/01/01
maps: {k1: v1,k2: v2}
lists:
- code
- girl
- music
dog:
name: ${person.hello:other}_旺财
age: 1
3.3 Properties和Yaml的对比小结
@Value这个使用起来并不友好!我们需要为每个属性单独注解赋值,比较麻烦;我们来看个功能对比图
1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加
2、松散绑定:这个什么意思呢? 比如我的yaml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下
3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性
4、复杂类型封装,yaml中可以封装对象 , 使用value就不支持。
4、JSR303数据校验及多环境切换
JSR303数据校验是用来校验输入内容的
Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的name只能支持Email格式;
@Component //注册bean
@ConfigurationProperties(prefix = "person")
@Validated //数据校验
public class Person {
@Email(message="邮箱格式错误") //name必须是邮箱格式
private String name;
}
yaml的多文档块 - 使用profiles激活其中一个
和properties配置文件中一样,但是使用yml去实现不需要创建多个配置文件,更加方便了 ! 通过---来分割模块
server:
port: 8081
#选择要激活那个环境块
spring:
profiles:
active: prod
---
server:
port: 8083
spring:
profiles: dev #配置环境的名称
---
server:
port: 8084
spring:
profiles: prod #配置环境的名称
5、自动配置原理、
在之前我们的项目都是以jar包结尾的,没有放webapp的地方。 springboot最大的特点:自动装配
1.创建应用,选择模块导入starter,只需要专注于业务代码
springboot到底帮我们配置了什么,我们能不能修改?能修改哪些东西?能不能扩展
-
xxxAutoConfiguration:向容器中自动配置组件
-
xxxProperties:自动配置类,装配配置文件中自定义的一些内容 要解决的问题:
-
导入静态资源html,css,js
-
首页
-
写jsp的地方,模板引擎Thymeleaf
-
装配和扩展SpringMVC
-
增删改查
-
拦截器
6、springboot Web开发总览
webjars - 静态资源引入
Webjars本质就是以jar包的方式引入我们的静态资源 , 我们以前要导入一个静态资源文件,直接导入即可。
使用SpringBoot需要使用Webjars,我们可以去搜索一下:
要使用jQuery,我们只要要引入jQuery对应版本的pom依赖即可!
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
所以得出结论,以下四个目录存放的静态资源可以被我们识别
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"
我们也可以自己通过配置文件来指定一下,哪些文件夹是需要我们放静态资源文件的,在application.properties中配置;
spring.resources.static-locations=classpath:/coding/,classpath:/kuang/
关闭默认图标-高版本我并未修改成
#关闭默认图标
spring.mvc.favicon.enabled=false
7、Thymeleaf模版引擎
7.1 模板引擎
前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等。
jsp支持非常强大的功能,包括能写Java代码,但是呢,我们现在的这种情况,SpringBoot这个项目首先是以jar的方式,不是war,像第二,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp的。
那不支持jsp,如果我们直接用纯静态页面的方式,那给我们开发会带来非常大的麻烦,那怎么办呢?
SpringBoot推荐你可以来使用模板引擎:
模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想都是一样的,什么样一个思想呢我们来看一下这张图:
模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。只不过呢,就是说不同模板引擎之间,他们可能这个语法有点不一样。其他的我就不介绍了,我主要来介绍一下SpringBoot给我们推荐的Thymeleaf模板引擎,这模板引擎呢,是一个高级语言的模板引擎,他的这个语法更简单。而且呢,功能更强大。
7.2引入Thymeleaf
Thymeleaf 官网:www.thymeleaf.org/
Thymeleaf 在Github 的主页:github.com/thymeleaf/t…
Spring官方文档:找到我们对应的版本 docs.spring.io/spring-boot…
导包
springboot一定不能直接去官网copy,得采用spring-boot-starter
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
只需要把我们的html页面放在类路径下的templates下,thymeleaf就可以帮我们自动渲染了
1、编写一个TestController
package com.example.springcool.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController {
@RequestMapping("/test")
public String test() {
//classpath:/templates/test.html
return "test";
}
}
2、编写一个测试页面 test.html 放在 templates 目录下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>test</h1>
</body>
</html>
3、结果
我们做个最简单的练习 :我们需要查出一些数据,在页面中展示
1、修改测试请求,增加数据传输;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController {
@RequestMapping("/test")
public String test(Model model) {
//存入数据
model.addAttribute("msg","Hello,Thymeleaf");
//classpath:/templates/test.html
return "test";
}
}
2、我们要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。
我们可以去官方文档的#3中看一下命名空间拿来过来:
xmlns:th="http://www.thymeleaf.org"
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--th:text就是将div中的内容设置为它指定的值,和之前学习的Vue一样-->
<h1 th:text="${msg}"></h1>
</body>
</html>
7.3 Thymeleaf语法
8、springMVC自动配置原理
8.1 自动配置原理
官网3.2.0 GA docs.spring.io/spring-boot…
在SpringBoot中会有非常多的扩展配置(非AutoConfig),只要看见了这个,我们就应该多留心注意~
package com.example.springcool.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class MyMvcConfig implements WebMvcConfigurer {
}
9、springboot整合数据库
数据库连接池负责分配、管理和释放数据库连接。它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放而引起的连接遗漏。这项技术能明显提高对数据库操作的性能。简言之,就是一个池子,里面放着数据库连接,应用服务需要的时候就去池子里面拿,用完之后归还给池子。下面介绍两种常见的数据库连接池 Druid HikariCP
9.1 整合Druid - 监控数据库
下面是使用springboot3.2.0,貌似springboot3和2的区别挺大的,这里操作有所变化。以mysql为例,导入依赖:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!--SpringBoot3-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.18</version>
</dependency>
<!--JDBC+MYSQL-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
配置文件如下:
spring:
datasource:
druid:
username: root
password: root
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://localhost:3306/springBoot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
db-type: com.alibaba.druid.pool.DruidDataSource
#Spring Boot 默认是不注入这些属性值的,需要自己绑定
#druid 数据源专有配置
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
max-pool-prepared-statement-per-connection-size: 20
use-global-data-source-stat: true
filter:
stat:
merge-sql: true
slow-sql-millis: 50
proxy-filters: stat,wall,log4j
这里是不同于2的,应该是3不适配druid造成的
resource下创建
META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports文件
resources\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports
添加com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure
添加配置类,新建config文件下:
package com.example.springboot_druid.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.jakarta.StatViewServlet;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.HashMap;
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource(){
return new DruidDataSource();
}
//后台监控 相当于web.xml
//因为SpringBoot 内置了 servlet容器,所以没有web.xml,替代方法:ServletRegistrationBean
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
//后台需要有人登录,账号和密码设置
HashMap<String , String> initParameters = new HashMap<>();
//增加配置
initParameters.put("loginUsername","admin");//登录key 是固定的 LoginUsername LoginPassword
initParameters.put("loginPassword","123456");
//允许谁可以访问
initParameters.put("allow","");//这个代表都能访问
//禁止谁能访问 initParameters.put("Massimo","192.168.11.123");
bean.setInitParameters(initParameters);//设置初始化参数
return bean;
}
}
可以在测试类里,打印出信息
@SpringBootTest
class SpringbootDataJdbcApplicationTests {
//DI注入数据源
@Autowired
DataSource dataSource;
@Test
public void contextLoads() throws SQLException {
//看一下默认数据源
System.out.println(dataSource.getClass());
//获得连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
DruidDataSource druidDataSource = (DruidDataSource) dataSource;
System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());
//关闭连接
connection.close();
}
}
现在控制台打印如下,能看到连接池变成druid,不清楚打印问题,这里不管重点不在这
打开网页输入 : localhost:8080/druid ,就可以监控数据库了,可以查看sql操作
配置 Druid web 监控 filter 过滤器
//配置 Druid 监控 之 web 监控的 filter
//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
@Bean
public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
//exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
Map<String, String> initParams = new HashMap<>();
initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");
bean.setInitParameters(initParams);
//"/*" 表示过滤所有请求
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
注意点:DruidConfig文件一定要添加配置注解,在里面配置的一些servlet和filter都要添加@Bean注解
9.2 整合HikariCP
waiting。。。
9.3 整合mybatis
导入依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
配置数据库连接信息
mybatis:
type-aliases-package: com.example.springboot_mybatis
mapper-locations: classpath:mybatis/mapper/*.xml
创建实体类
@Data 使用这个注解可以省去代码中大量的get()、 set()、 toString()等方法
@AllArgsConstructor 类的全参构造
@NoArgsConstructor 类的无参构造
public class User {
private Integer id;
private String name;
private String pwd;
}
创建mapper目录以及对应的 Mapper 接口
@Mapper
@Repository
public interface UserMapper {
public static final int age=18;
List<User> queryUserList();
User queryUserById(Integer id);
int addUser(User user);
int updateUser(User user);
int deleteUserById(Integer id);
}
接下来该去配置mapper.xml文件了,这里建议创建在resources的目录下:(增删改查操作)
暂时先不写service层,直接写controller调用mapper
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/list")
public List<User> List(){
return userMapper.queryUserList();
}
}
10、springSecurity6-版本大变动
springSecurity6变动
从 Spring Security5.7 开始(对应 Spring Boot2.7 开始),很多用法都大变动:
- WebSecurityConfigurerAdapter 过期,过期的原因是因为官方想要鼓励各位开发者使用基于组件的安全配置
以前我们配置 SecurityFilterChain 的方式是下面这样:
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
)
.httpBasic(withDefaults());
}
}
那么以后就要改为下面这样了:
@Configuration
public class SecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
)
.httpBasic(withDefaults());
return http.build();
}
}
以前我们配置 WebSecurity 是这样:
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/ignore1", "/ignore2");
}
}
以后就得改成下面这样了:
@Configuration
public class SecurityConfiguration {
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2");
}
}
另外还有一个就是关于 AuthenticationManager 的获取,以前可以通过重写父类的方法来获取这个 Bean,类似下面这样:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
以后就只能自己创建这个 Bean 了,类似下面这样:
@Configuration
public class SecurityConfig {
@Autowired
UserService userService;
@Bean
AuthenticationManager authenticationManager() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userService);
ProviderManager pm = new ProviderManager(daoAuthenticationProvider);
return pm;
}
}
当然,也可以从 HttpSecurity 中提取出来 AuthenticationManager,如下:
@Configuration
public class SpringSecurityConfiguration {
AuthenticationManager authenticationManager;
@Autowired
UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.userDetailsService(userDetailsService);
authenticationManager = authenticationManagerBuilder.build();
http.csrf().disable().cors().disable().authorizeHttpRequests().antMatchers("/api/v1/account/register", "/api/v1/account/auth").permitAll()
.anyRequest().authenticated()
.and()
.authenticationManager(authenticationManager)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
springSecurity5.7之前
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
- WebSecurityConfigurerAdapter:自定义Security策略
- AuthenticationManagerBuilder:自定义认证策略
- @EnableWebSecurity:开启WebSecurity模式
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
“认证”(Authentication)
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。 身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。这个概念是通用的,而不是只在Spring Security 中存在。
科普一个接口传参的查询用法,工作中很常见:
引入thymeleaf依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>3.1.6</version>
</dependency>
配置文件
写一个访问页面的接口
访问界面
导入security的依赖(到这新版不支持继承功能)
<!--SpringSecurity -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
新建一个配置文件,并且继承 WebSecurityConfigurerAdapter,并且要添加@EnableWebSecurity注解
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasAnyRole("vip1")
.antMatchers("/level2/**").hasAnyRole("vip2")
.antMatchers("/level3/**").hasAnyRole("vip3");
}
}
注意这里用到了链式
测试一下:发现除了首页都进不去了!因为我们目前没有登录的角色,因为请求需要登录的角色拥有对应的权限才可以!
在configure()方法中加入以下配置,开启自动配置的登录功能!
// 开启自动配置的登录功能
// /login 请求来到登录页
// /login?error 重定向到这里表示登录失败
http.formLogin();
测试发现没有权限的时候,会跳转到登录的页面:
查看刚才登录页的注释信息;我们可以定义认证规则,重写configure(AuthenticationManagerBuilder auth)方法 也可以去jdbc中去取
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
auth.inMemoryAuthentication()
.withUser("kuangshen").password("123456").roles("vip2","vip3")
.and()
.withUser("root").password("123456").roles("vip1","vip2","vip3")
.and()
.withUser("guest").password("123456").roles("vip1");
}
测试,我们可以使用这些账号登录进行测试!发现会报错!
原因,我们要将前端传过来的密码进行某种方式加密,否则就无法登录,修改代码
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
//Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
//要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
//spring security 官方推荐的是使用bcrypt加密方式。
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
}
测试,发现,登录成功,并且每个角色只能访问自己认证下的规则!
开启自动配置的注销的功能
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
//....
//开启自动配置的注销的功能
// /logout 注销请求
http.logout();
}
我们在前端,增加一个注销的按钮,index.html 导航栏中
<a class="item" th:href="@{/logout}">
<i class="sign-out icon"></i> 注销
</a>
我们可以去测试一下,登录成功后点击注销,发现注销完毕会跳转到登录页面!
但是,我们想让他注销成功后,依旧可以跳转到首页,该怎么处理呢?
// .logoutSuccessUrl("/"); 注销成功来到首页
http.logout().logoutSuccessUrl("/");
测试,注销完毕后,发现跳转到首页OK
我们现在又来一个需求:用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮!还有就是,比如kuangshen这个用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能,而vip1的功能菜单不显示!这个就是真实的网站情况了!该如何做呢?
我们需要结合thymeleaf中的一些功能
sec:authorize=“isAuthenticated()”:是否认证登录!来显示不同的页面
导入thymeleaf和security结合的Maven依赖:
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
修改我们的 前端页面
导入命名空间
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
修改导航栏,增加认证判断
<!--登录注销-->
<div class="right menu">
<!--如果未登录-->
<div sec:authorize="!isAuthenticated()">
<a class="item" th:href="@{/login}">
<i class="address card icon"></i> 登录
</a>
</div>
<!--如果已登录-->
<div sec:authorize="isAuthenticated()">
<a class="item">
<i class="address card icon"></i>
用户名:<span sec:authentication="principal.username"></span>
角色:<span sec:authentication="principal.authorities"></span>
</a>
</div>
<div sec:authorize="isAuthenticated()">
<a class="item" th:href="@{/logout}">
<i class="address card icon"></i> 注销
</a>
</div>
</div>
重启测试,我们可以登录试试看,登录成功后确实,显示了我们想要的页面;
如果注销404了,就是因为它默认防止csrf跨站请求伪造,因为会产生安全问题,我们可以将请求改为post表单提交,或者在spring security中关闭csrf功能;我们试试:在 配置中增加 http.csrf().disable();
目前为止已近实现了权限的访问资源不同,接下来还想实现对不同用户的页面显示内容不同:
关键代码:sec:authorize=“hasRole()” //判断当前的权限是否有这个权限直接加在想要设置权限的标签内即可
现在的情况,我们只要登录之后,关闭浏览器,再登录,就会让我们重新登录,但是很多网站的情况,就是有一个记住密码的功能,这个该如何实现呢?很简单,开启记住我功能
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
//...
//记住我
http.rememberMe();
}
我们再次启动项目测试一下,发现登录页多了一个记住我功能,我们登录之后关闭 浏览器,然后重新打开浏览器访问,发现用户依旧存在!浏览器cookie的保存日期默认为14天
现在这个登录页面都是spring security 默认的,怎么样可以使用我们自己写的Login界面呢?在刚才的登录页配置后面指定 loginpage
http.formLogin().loginPage("/toLogin");
前端也需要指向我们自己定义的 login请求
<a class="item" th:href="@{/toLogin}">
<i class="address card icon"></i> 登录
</a>
我们登录,需要将这些信息发送到哪里,我们也需要配置,login.html 配置提交请求及方式,方式必须为post:
<form th:action="@{/toLogin}" method="post">
这个请求提交上来,我们还需要验证处理,怎么做呢?我们可以查看formLogin()方法的源码!我们配置接收登录的用户名和密码的参数!这时就需要去config中设置一下,将对应的字段进行连接
http.formLogin().usernameParameter("name").passwordParameter("pwd").loginPage("/toLogin1");
在登录页增加记住我的选择框
<input type="checkbox" name="remember"> 记住我
http.rememberMe().rememberMeParameter("remember");
springSecurity6
使用mybatis-plus作为ORM框架,然后使用springsecurity6作为安全框架,采用JWT作为权限确认的方式
这个人写的挺好的,我就直接上链接,跟着做了一遍,是能正常读取数据库中密码blog.csdn.net/m0_71273766…
这里附赠一个介绍JWT的学习网址:juejin.cn/post/705915…
导入的spring-security6 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!--解决高版本JDK问题-->
<!--javax.xml.bind.DatatypeConverter错误-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-extra -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId>
<version>5.8.21</version>
</dependency>
11、shiro
新版的springboot3.2.0无法适配shiro,配置完后无法使用,我也一直没解决出来,但是感觉shiro比spring-security操作时简单的,找到了一个配享太庙的博客,整合了springboot3+shiro:zhuanlan.zhihu.com/p/663925382
springboot3以上版本导入依赖:
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<classifier>jakarta</classifier>
<version>1.12.0</version>
<!-- 排除仍使用了javax.servlet的依赖 -->
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入适配jakarta的依赖包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<classifier>jakarta</classifier>
<version>1.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<classifier>jakarta</classifier>
<version>1.12.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
</exclusions>
</dependency>
12、swagger
这块建议用最新的knife4j,我单独写了一个mybatis-plus的博客使用
springboot3集成swagger3
之前springboot3.0之前用的都是Springfox来集成Swagger管理我们的API接口文档,这也就是Springfox和Springdoc最主要的功能。因为Springfox已经停止更新有段时间了,升级Springboot3.0以后会有更多问题暴露出来。Spring官网推荐了Springdoc,应该不会短时间停更,所以改用Springdoc
添加依赖
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<version>2.0.2</version>
</dependency>
从Springfox迁移过来的,需要修改注解:
@Api -> @Tag
@ApiIgnore -> @Parameter(hidden = true) 或 @Operation(hidden = true) 或 @Hidden
@ApiImplicitParam -> @Parameter
@ApiImplicitParams -> @Parameters
@ApiModel -> @Schema
@ApiModelProperty(hidden = true) -> @Schema(accessMode = READ_ONLY)
@ApiModelProperty -> @Schema
@ApiOperation(value = "foo", notes = "bar") -> @Operation(summary = "foo", description = "bar")
@ApiParam -> @Parameter
@ApiResponse(code = 404, message = "foo") -> @ApiResponse(responseCode = "404", description = "foo")
yml的配置文件(应该还有好多,我学习就先试试这点)
server:
port: 8080
springdoc:
swagger-ui:
path: /swagger-ui.html
# 持久化认证数据,如果设置为 true,它会保留授权数据并且不会在浏览器关闭/刷新时丢失
persistAuthorization: true
api-docs:
# 是否开启接口文档
enabled: true
# Logger Config
logging:
level:
com.hexadecimal: debug
随便写个测试接口
package com.example.swaggerdemo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class testController {
@RequestMapping("/test")
public String test(){
return "test";
}
}
写个配置类
package com.example.swaggerdemo.config;
import org.springframework.context.annotation.Configuration;
@Configuration //配置类
public class SwaggerConfig {
@Bean //配置接口文档的标题、描述、版本、license等信息
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("文档标题")
.description("文档描述")
.version("v1")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("外部文档")
.url("https://springshop.wiki.github.org/docs"));
}
}
访问界面http://localhost:8080/swagger-ui/index.html
13、任务
13.1 异步任务
开启两个注解
@Async
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据正在传输...");
}
@EnableAsync
@SpringBootApplication
public class SwaggerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SwaggerDemoApplication.class, args);
}
}
13.2 邮件任务
导入依赖
<!--javax mail-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
添加配置
spring.mail.username=2509575042@qq.com
spring.mail.password=hzajiriiyrlvdhhd
spring.mail.host=smtp.qq.com
spring.mail.port=587
spring.mail.protocol=smtp
# qq需要配置ssl,其他邮箱不需要
spring.mail.properties.mail.smtp.auth=true
spring.mail.default-encoding=UTF-8
spring.mail.properties.mail.debug=true
简单邮件和带附件的
@Resource
private JavaMailSender jsm;
@Test //简单邮件
void contextLoads() {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom("2509575042@qq.com");
simpleMailMessage.setTo("tangding315@126.com");
simpleMailMessage.setSubject("测试邮件标题");
simpleMailMessage.setText("测试邮件内容");
jsm.send(simpleMailMessage);
}
@Test //复杂邮件
void contextLoads1() throws MessagingException {
MimeMessage message = jsm.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom("2509575042@qq.com");
helper.setTo("tangding315@126.com");
helper.setSubject("测试邮件标题");
helper.setText("<b style='color:red'>今天 7:30来开会</b>",true);
//发送附件
helper.addAttachment("test.xls",new File("C://Users//damon//Desktop//test.xls"));
jsm.send(message);
}
13.3 定时任务
项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口。
- TaskExecutor接口 任务执行者
- TaskScheduler接口 任务调度者
两个注解:
- @EnableScheduling 开启定时功能的注解
- @Scheduled 什么时候开启
@EnableAsync //开启异步注解功能
@EnableScheduling //开启基于注解的定时任务
@SpringBootApplication
public class SpringbootTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTaskApplication.class, args);
}
}
@Service
public class ScheduledService {
@Scheduled(cron = "0 25 15 * * 0-7")
public void hello(){
System.out.println("hello.....");
}
}
常用Corn--- (秒 分 时 日 月 星期[0-7,其中0和7都是星期天])
(1)0/2 * * * * ? 表示每2秒 执行任务
(1)0 0/2 * * * ? 表示每2分钟 执行任务
(1)0 0 2 1 * ? 表示在每月的1日的凌晨2点调整任务
(2)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
(3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(4)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
(6)0 0 12 ? * WED 表示每个星期三中午12点
(7)0 0 12 * * ? 每天中午12点触发
(8)0 15 10 ? * * 每天上午10:15触发
(9)0 15 10 * * ? 每天上午10:15触发
(10)0 15 10 * * ? 每天上午10:15触发
(11)0 15 10 * * ? 2005 2005年的每天上午10:15触发
(12)0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
(13)0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
(14)0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(15)0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
(16)0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
(17)0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
(18)0 15 10 15 * ? 每月15日上午10:15触发
(19)0 15 10 L * ? 每月最后一日的上午10:15触发
(20)0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
(21)0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
(22)0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
14、Dubbo和Zookeeper集成
Apache Dubbo 是一款易用、高性能的 WEB 和 RPC 框架,同时为构建企业级微服务提供服务发现、流量治理、可观测、认证鉴权等能力、工具与最佳实践。它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
Zoookeeper,它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。简单来说zookeeper=文件系统+监听通知机制。简单来说==管理分布式程序部署