yaml配置(application.yaml)

# k=v
# 对空格的要求十分高
# 普通的key-value

#普通的key-value
name: xiaoming

#对象
student:
  name: xiaoming
  age: 3

#行内写法
student: {name: xiaoming,age: 3}

#数组
pets:
  - cat
  - dog
  - pig

pets: [cat,dog,pig]

不使用yaml:

@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
//@ConfigurationProperties(prefix = "dog")
public class Dog {
    @Value("旺财")
    private String name;
    @Value("3")
    private Integer age;
}

使用yaml:

@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
@ConfigurationProperties(prefix = "dog")//不配置时把报红,但不影响使用
public class Dog {
//    @Value("旺财")
    private String name;
//    @Value("3")
    private Integer age;
}

application.yaml:

dog:
  name: 旺财
  age: 3

指定配置文件:

xxx.properties
需要在pojo类上加上注解
@PropertySource(value = "classpath:xxx.properties")
SPEL表达式去除配置中的值
@Value("${name}")
private String name;

特殊用法

dog:
  name: ${random.uuid}
  age: ${random.int}
# 如果前面的值存在去前面的值,否则取后面的值
  name1: ${dog.name:旺财}

松散绑定

比如yaml中为last-name,这个和lastName是一样的,-后面跟着的字母是默认大写的

JSR303校验

需要导入依赖spring-boot-starter-validation
@Validated//数据校验(类上边)
@Email(message="邮箱格式错误")(属性上)
数据校验不能和Value同时使用

配置文件位置

1.file:./config/(优先级最高)(根目录)
2.file:./
3.classpath:/config/
4.classpath:/(优先级最低)(resources目录)

静态资源

webjars localhost:8080/webjars/
public,static,/**,resources(全部为resources目录下) localhost:8080/
优先级:resources>static(默认)>public

thymeleaf

修改 pom.xml, 增加对 thymeleaf 的支持

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>  
</dependency>

html要声明
<html xmlns:th="http://www.thymeleaf.org">

所有的html元素都可以被thymeleaaf替换接管:
th: 元素名
<h1 th:text="${msg}"></h1>

字符串拼写。 两种方式,一种是用加号,一种是在前后放上 ||, 显然第二种方式可读性更好。
<p th:text="'Hello! ' + ${name} + '!'" >hello world</p>
<p th:text="|Hello! ${name}!|" >hello world</p>

SpringSecurity

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
package com.song.springboot.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 Security extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/test").hasRole("vip1")
                .antMatchers("/h1").hasRole("vip2");
        http.formLogin();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
                .and()
                .withUser("qwe").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
    }
}

shiro

概念

Application Code:代表着应用,应用使用Subject来标识自己的身份,以及使用Subject来进行认证和授权。
Subject:代表着“当前用户”。
Shiro SecurityManager:应用使用Subject来进行认证和授权,实际上执行认证和授权的是SecurityManager
Realm:SecurityManager的认证和授权需要使用Realm,Realm负责获取用户的权限和角色等信息,再返回给SecurityManager来进行判断。

原理

当调用ShiroHandler中的subject.login()的时候,会自动调用Realm中的doGetAuthenticationInfo方法
subject.hasRole 判断Subject是否拥有该角色,会自动调用Realm中的doGetAuthorizationInfo方法
Subject.isPermitted(permission)已登陆用户判断是否具有某权限,会自动调用Realm中的doGetAuthorizationInfo方法

如何验证

shiro会校验info和token,Token和SimpleAuthenticationInfo的credentials做对比,进行验证。
SimpleAuthenticationInfo放盐值
HashedCredentialsMatcher放加密算法和加密次数

访问

anon: 无需认证即可访问
authc: 需要认证才可访问
user: 点击“记住我”功能可访问
perms: 拥有权限才可以访问
role: 拥有某个角色权限才能访问

动态代理

利用反射机制在运行时创建代理类。
接口、被代理类不变,我们构建一个handler类来实现InvocationHandler接口。

public class ProxyHandler implements InvocationHandler{
    private Object object;
    public ProxyHandler(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke "  + method.getName());
        method.invoke(object, args);
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

执行动态代理:

    public static void main(String[] args) {
        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        HelloInterface hello = new Hello();

        InvocationHandler handler = new ProxyHandler(hello);

        HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);

        proxyHello.sayHello();
    }
    输出:
    Before invoke sayHello
    Hello zhanghao!
    After invoke sayHello

通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例。针对不同的代理类,传入相应的代理程序控制器InvocationHandler。
如果新来一个被代理类Bye,如:

public interface ByeInterface {
    void sayBye();
}
public class Bye implements ByeInterface {
    @Override
    public void sayBye() {
        System.out.println("Bye zhanghao!");
    }
}

那么执行过程:

    public static void main(String[] args) {
        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        HelloInterface hello = new Hello();
        ByeInterface bye = new Bye();

        InvocationHandler handler = new ProxyHandler(hello);
        InvocationHandler handler1 = new ProxyHandler(bye);

        HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);

        ByeInterface proxyBye = (ByeInterface) Proxy.newProxyInstance(bye.getClass().getClassLoader(), bye.getClass().getInterfaces(), handler1);
        proxyHello.sayHello();
        proxyBye.sayBye();
    }
    输出:
    Before invoke sayHello
    Hello zhanghao!
    After invoke sayHello
    Before invoke sayBye
    Bye zhanghao!
    After invoke sayBye

WebMvcConfigurerAdapter

public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
    /*配置路径匹配参数*/
    public void configurePathMatch(PathMatchConfigurer configurer) {}
    /*配置Web Service或REST API设计中内容协商,即根据客户端的支持内容格式情况来封装响应消息体,如xml,json*/
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}
    /*配置路径匹配参数*/
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {}
    /* 使得springmvc在接口层支持异步*/
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}
    /* 注册参数转换和格式化器*/
    public void addFormatters(FormatterRegistry registry) {}
    /* 注册配置的拦截器*/
    public void addInterceptors(InterceptorRegistry registry) {}
    /* 自定义静态资源映射*/
    public void addResourceHandlers(ResourceHandlerRegistry registry) {}
    /* cors跨域访问*/
    public void addCorsMappings(CorsRegistry registry) {}
    /* 配置页面直接访问,不走接口*/
    public void addViewControllers(ViewControllerRegistry registry) {}
    /* 注册自定义的视图解析器*/
    public void configureViewResolvers(ViewResolverRegistry registry) {}
    /* 注册自定义控制器(controller)方法参数类型*/
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {}
    /* 注册自定义控制器(controller)方法返回类型*/
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {}
    /* 重载会覆盖掉spring mvc默认注册的多个HttpMessageConverter*/
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}
    /* 仅添加一个自定义的HttpMessageConverter,不覆盖默认注册的HttpMessageConverter*/
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}
    /* 注册异常处理*/
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {}
    /* 多个异常处理,可以重写次方法指定处理顺序等*/
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {}
}

才子词人,自是白衣卿相