SpringBoot

2020-02-14  本文已影响0人  dillqq

@SpringBootAplication 表示主程序类 或者说是主配置类,表示这是一个sprongboot应用
SpringAplication.run(主程序类名.class,args)启动spring程序

start启动器,直接引入了版本和版本号,可以防止版本冲突。
spring-boot-start-xxx:场景启动器

springboot项目下的扫描的组件必须在主配置类包下,这样才能扫描到容器中

@EnableAutoConfiguration 通过spring.properties文件获取 自动配置类

resource目录结构
static:保存静态资源
templates:保存模板,不支持jsp,但支持模板引擎
application.properties:应用的配置文件 固定文件名

YAML:
1.注意语法,以空格表示层级
2.值有三种:字变量 ” 不会转义,对象,数组

@ConfigurationProperties(prefix=“xxx”):这个注解的作用是将本类的属性与配置文件中属性互相绑定,而且必须使用@Component注册到容器中

添加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

@Value注解,注入值 ¥{xxx},从配置文件中获取值,#{SpEL}比如#{11*2}

@Valid 用在类名上用于校验启动JSR303,@Email用于邮箱校验

@PropertySource(value = {"classpath:person.properties"})作用于改变加载默认配置文件

@ImportResource( locations = {"classpath:person.xml"})这个用于主配置类下,用于将配置加入容器中

@Configuration :表明这是一个配置类

profiles作用是在不同条件下使用不同配置:在配置文件中这么设置spring.profiles.active=xxx,配置文件命名规则application-xxx.properties

日志,logging.file=xxx.log

中文编码问题:

  spring.http.encoding.force=true
  spring.http.encoding.charset=UTF-8
  spring.http.encoding.enabled=true
  server.tomcat.uri-encoding=UTF-8

SpringBoot对静态资源的映射规则:
1)、webjars,以jar包的形式引入所有都在webjars/,在classpath:/META-INF/resources/webjars。搜索webjar,引入对应的maven坐标
2)、“/
”访问当前项目下的所有资源,查找路径,“classpath:/META-INF/resources”,"classpath:/resources/","classpath:/static/","classpath:/public/"
3)、欢迎页面为index.html
4)、所有的**/favicon.ico都是在静态资源文件下

Thymeleaf

1)、引入坐标

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

2)、导入命名空间

  <html lang="en" xmlns:th="http://www.thymeleaf.org">

3)、使用语法

th:text:指定文本内容
th:任意html元素
${...}:1.获取对象的属性、调用方法、
2.使用内置对象
3.内置的一些工具对象

/ #{...}:获得国际化内容
@{...}:定义URL链接的
~{...}:片段引用的表达式

视图解析器,只需要自己编写一个视图解析器,容器就会将他加入进来

自动注册Converter:转换器,Formatter:格式化器,

修改SpringBoot默认配置,先看容器中有没有用户自己配置的组件,如果有则导入用户自己配置的组件

1)、WebMvcAutoConfiguration是SpringBoot的自动配置类
2)、在做其他配置时自动导入
3)、WebMvcConfigurer会一起作用
4)、自己写的配置类也会被调用

@EnableMVC 全面接管SpringMVC

WebMvcConfigurerAdapter组件都会一起起作用

@Configuration//配置类
public class MyConfiguration implements WebMvcConfigurer {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/hello").setViewName("index");
}
}

国际化
1)、抽取国际化配置文件,抽取页面需要显示的国际化消息
2)、创建文件i18n,
xxx.properties;
xxx_zh_CN.properties;
person_zh_CN.properties

3)、点击下列Resource Bundle,添加KV
4)、设置国际化资源位置spring.messages.basename=i18n.xxx
5)、去页面获取国际化的值,thymeleaf使用#{xxx}取得国际化的值

MessageSourceAutoConfiguration

国际化原理:获取区域信息对象,localeResolver ,根据request的获取区域信息进行国际化

通过按钮实现语言切换功能@{/index}:,继承LocalResolver,

public class MyLocalResolver implements LocaleResolver {

@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
    String i = httpServletRequest.getParameter("l");
    Locale locale =Locale.getDefault();
    if (!StringUtils.isEmpty(i))
    {
        String[] split = i.split("_");
        locale = new Local(split[0], split[1]);
        return locale;
    }
    return locale;
}

@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

}
}

@RequestParam("xxx") 必须提交的参数

spring.thymeleaf.cache=false 将thymeleaf缓存取消。然后按Crtl+F9,更新页面

   #xxx使用内置对象

拦截器机制

  public class LoginHandleIntercepter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    Object s = request.getSession().getAttribute("loginUser");
    if (s==null)
    {
        request.setAttribute("msg","没有权限");
        request.getRequestDispatcher("/").forward(request,response);
        return false;
    }else {
        return true;
    }
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

}
}

需要在配置类中添加组件

RestfulCRUD与普通CRUD的区别是,使用特定的请求方式来完成数据操作

spring.mvc.date-format=yyyy-MM-dd HH:mm 

指定date格式

@PathVariable("xxx") 获取路径变量的值

<input type = "hidden"  name ="_method" value='put" th:if="${emp != null}">

用于修改action请求方式

th:attr="xx=xx" 设置属性创建值

错误处理机制
ErrorMvcAutoConfiguration

BasicErrorController:处理默认的/error请求

ErrorPageCustomizer:作用出现错误以后来到/error请求

DefaultErrorAttributes:作用帮我调用共享页面属性,
timestamp:时间戳
status:状态码
error:错误的提示
exception:异常
message:异常的消息
errors:JSR303数据校验的错误

DefaultErrorViewResolver:解析视图名,定位到/error目录下,根据错误码返回页面。如果模板引擎可以用,就是用模板引擎,如果不行就使用静态路径下的资源。定制错误页面,就把定制页面的名字写为错误状态吗,放在templates下的error文件下,或者命名为4xx或者5xx来代替一类错误页面

总结:一旦系统出现4xx或者5xx之类的错误,ErrorPageCustomizer会生效来到/error请求,而一来到/error请求,就会被BasicErrorController处理请求 (两种请求方式,浏览器和客户端请求,根据请求头区别),响应页面是由DefaultErrorViewResolver解析,

@ControllerAdvice
public class MyEceptionHandler {

@ResponseBody
@ExceptionHandler(MyException.class)
public Map<String, Object> handlerException(Exception e)
{
    Map<String, Object> map = new HashMap<>();
    map.put("name","zheng");
    return map;
}
}

2、错误码页面

  @ControllerAdvice
public class MyEceptionHandler {


@ExceptionHandler(MyException.class)
public String handlerException(Exception e, HttpServletRequest request)
{
    Map<String, Object> map = new HashMap<>();
    request.setAttribute("javax.servlet.error.status_code",400);
    map.put("name","zheng");
    request.setAttribute("ext",map);
    return "forward:/error";
}
}

json数据重建

@Component
public class MyErrorAttribute extends DefaultErrorAttributes {

@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
    Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
    Map<String, Object> map1 = (Map<String, Object>)webRequest.getAttribute("ext", 0);
    map.put("ext",map1);
    return map;
}
}

注册三大组件

@Configuration
  public class MyConfiguration implements WebMvcConfigurer {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/hello").setViewName("index");
}


@Bean
public ServletRegistrationBean myServlet()
{
    ServletRegistrationBean<MyServlet> servlet = new ServletRegistrationBean<MyServlet>(new MyServlet(), "/exception");
    return servlet;
}

@Bean
public FilterRegistrationBean myFilter()
{
    FilterRegistrationBean<MyFilter> filter = new FilterRegistrationBean<MyFilter>();
    filter.setFilter(new MyFilter());
    filter.setUrlPatterns(Arrays.asList("/exception"));
    return filter;
}

@Bean
public ServletListenerRegistrationBean myListener()
{
    ServletListenerRegistrationBean<MyListener> listener = new ServletListenerRegistrationBean<>(new MyListener());
    return listener;
}

}

docker:提供镜像发布,直接下载容器启用
docker(主机);安装了docker程序的机器
docker(客户端):连接主机进行操作
docker(仓库);用来保存各种软件镜像的地方
docker(镜像):打包好的镜像,放在仓库中
docker(容器):镜像一启动就会创建一个容器

docker命令:
检索 docker search 关键字
下载 docker pull 镜像名
列表:查看本地所有镜像 docker images
删除 docker rmi image-id
容器操作
运行 docker run --name(定义名字) container-name -d(后台运行) image-name(指定镜像模板)

查看容器运行列表:docker ps
查看所有容器列表:docker ps -a
停止容器:docker stopt container-name/container-id
启动容器:docker start container-name/container-id
删除容器:docker rm container-name/container-id
端口映射:-p xxx:xxx 主机端口:容器内部端口
容器日志:docker logs container-name/container-id

使用mysql5.5,创建了容器重启一次服务器

mybatis

spring.datasource.username=root
spring.datasource.password=zheng
spring.datasource.url=jdbc:mysql://207.148.95.94/jdbc
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

  @RunWith(SpringRunner.class)
  @SpringBootTest
  class FirstbootApplicationTests {



@Autowired
DataSource dataSource;

@Test
void contextLoads() throws SQLException {
    System.out.println(dataSource.getClass());
    Connection connection = dataSource.getConnection();
    System.out.println(connection);
    connection.close();
}

}

指定数据源类型

spring.datasource.type=org.springframework.jdbc.datasource.DriverManagerDataSource

运行建表语句,运行插入数据语句:schama-.sql, data-.sql

使用druid数据源
第一引入坐标

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.16</version>
    </dependency>

第二,参数设置

spring.datasource.username=root
spring.datasource.password=zheng
spring.datasource.url=jdbc:mysql://207.148.95.94/jdbc
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

第三druid配置

  @Configuration
  public class DruidConfiguration {

@ConfigurationProperties("spring.datasource")
@Bean
public DruidDataSource dataSource(){
    return new DruidDataSource();
}

//配置Durid监控管理
@Bean
public ServletRegistrationBean statViewServlet(){
    ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");
    Map<String,String > map = new HashMap<>();
    map.put("loginUsername","admin");
    map.put("loginPassword","123456");
    map.put("deny","");
    map.put("allow","");
    bean.setInitParameters(map);
    return bean;
}


//web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
    FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>();
    bean.setFilter(new WebStatFilter());
    Map<String, String> initParams = new HashMap<>();
    initParams.put("exclusions","*.js,*.css,/druid/*");
    bean.setInitParameters(initParams);
    bean.setUrlPatterns(Arrays.asList("/*"));
    return bean;
}

}

定位sql的文件
spring.datasource.schema=xx.sql

使用mybatis

导入依赖

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.1</version>
    </dependency>

导入配置

spring.datasource.username=root
spring.datasource.password=zheng
spring.datasource.url=jdbc:mysql://207.148.95.94/jdbc
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

编写mapper

@Mapper
@Repository
public interface MyMapper {
@Select("select * from test where id =#{id}")
public testDomain findById(Integer integer);

@Delete("delete  from test where id=#{id}")
public Integer deleteById(Integer id);

@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("insert into test(name) values(#{name})")
public Integer insertTest(testDomain t);
}

编写控制层

@RestController
public class testController {

@Autowired
MyMapper testMapper;

@GetMapping("/find/{id}")
public testDomain findById(@PathVariable("id") Integer id){
    testDomain testDomain = testMapper.findById(id);
    System.out.println(testDomain);
    return testDomain;
}


@GetMapping("/delete/{id}")
public Integer deleteById(@PathVariable("id") Integer id){
    return testMapper.deleteById(id);
}


@GetMapping("/insert")
public Integer deleteById(testDomain testDomain){
    return testMapper.insertTest(testDomain);
}

}

解决扫描mapper包

@MapperScan("com.example.firstboot.Mapper")
@SpringBootApplication
public class FirstbootApplication {

public static void main(String[] args) {
    SpringApplication.run(FirstbootApplication.class, args);
}

}

mybatis xml文件mapper

mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

SpringData 是SpringBoot底层默认采用的访问数据库的技术,简化数据库的操作,统一数据访问的API,提供了各种temple类

SpringBoot启动配置原理
启动流程
1、创建SpringApplication对象,扫描初始化器ApplicationContextInitializer和监听器ApplicationListener
2、运行run方法

SpringApplicationRunListeners获取监听器执行

SpringBoot 场景启动器
启动器只用来导入依赖

https://blog.csdn.net/sgl520lxl/article/details/102495443

缓存JSR107
CachingProvider :控制和管理多个CachingManager,一个应用可以有多个CachingProvider

CacheManager:控制多个唯一命名的Cache、这些Cache存于CacheManager的上下文中

Cache是一个类似Map的数据结构。一个Cache只能被一个CacheManager使用

Entry:是一个存储在Cache中的KV对

Enpiry是一个存储在Cache条目中的一个有效期

springboot为了简化开发保留了:Cache和CacheManager

注解
@Cacheable:主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@CacheEvict:清空缓存
@CachePut:保证方法被调用,又希望结果被缓存
@EnableCaching:开启注解的缓存
@Caching可以使用Cacheable,CacheEvict,CachePut这三种的组合的缓存规则
keyGenerator:缓存数据时key的生成策略
serialize:缓存数据时value序列化的策略

使用

@SpringBootApplication
@EnableCaching//开启注解的缓存
public class Spring01DataApplication {

public static void main(String[] args) {
    SpringApplication.run(Spring01DataApplication.class, args);
}

}

持久层

@Mapper
@Repository
public interface testMapper {

@Select("select * from test where id = #{id}")
public testDomain findById(Integer id);

@Delete("delete  from test where id = #{id}")
public Integer deleteById(Integer id);

@Update("update test set name = #{name} where id =#{id}")
public Integer updateById(testDomain domain);

@Insert("insert into test(name) values(#{name})")
public Integer insert(testDomain domain);



}

业务层

  //这个类的默认设置
@CacheConfig(cacheNames = "person")
@Service
public class TestService {

@Autowired
com.zheng.spring_01_data.Mapper.testMapper testMapper;


/**
 * key :主键#root
 * keyGenerator主键生成器,
 * cacheManager:指定缓存管理器
 * condition:指定符合条件的情况下才缓存
 * unless:当符合条件返回值不会为true
 * sync是否使用异步表达式
 */
@Cacheable(cacheNames = {"person"})//,keyGenerator = "myKeyGenerator")
public String findById(Integer id){
    System.out.println("查询");
    testDomain domain = testMapper.findById(id);
    if (domain == null)
    {
        return "不存在";
    }
    return domain.toString();
}


/**
 * allEntries:指删除所有person的cache中的缓存
 * @param id
 * @return
 */
@CacheEvict(cacheNames = "person")
public String deleteById(Integer id){
    System.out.println("删除");
    return testMapper.deleteById(id).toString();
}


public String insert(){
    System.out.println("添加");
    testDomain domain = new testDomain();
    domain.setName("TEST1");
    return testMapper.insert(domain).toString();
}



@CachePut(cacheNames = "person")
public String update(Integer id){
    System.out.println("更改");
    testDomain domain = new testDomain();
    domain.setId(id);
    domain.setName("2323");
    return testMapper.updateById(domain).toString();
}
}

控制层

@RestController
public class TestController {

@Autowired
TestService testMapper;

@GetMapping("/findById")
public String findById(){
    return testMapper.findById(5);
}

@GetMapping("/delete")
public String deleteById(){
    return testMapper.deleteById(5);
}

@GetMapping("/insert")
public String insert(){
    return testMapper.insert();
}


@GetMapping("/update")
public String update(){

    return testMapper.update(5);
}
}

自定义key生成器

@Configuration
public class CacheConfig {

@Bean("myKeyGenerator")
public KeyGenerator keyGenerator(){
    return new KeyGenerator() {
        @Override
        public Object generate(Object o, Method method, Object... objects) {
            return method.getName()+'['+ Arrays.asList(objects)+']';
        }
    };
}
}

redis

append msg hello
get msg
http://www.redis.cn/

使用
1、在docker中安装redis
2、在pom文件中引入redis的坐标

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

3、配置redis

spring:
    redis:
      host: 207.148.95.94

4.配置类,如果使用对象存储到redis中会被序列化

@ConfigurationProperties(prefix = "spring.cache.redis")
@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<Object, testDomain> testRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
    RedisTemplate<Object, testDomain> template = new RedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    Jackson2JsonRedisSerializer<testDomain> testDomainJackson2JsonRedisSerializer;
    testDomainJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<testDomain>(testDomain.class);
    template.setDefaultSerializer(testDomainJackson2JsonRedisSerializer);
    return template;
}

private Duration timeToLive = Duration.ZERO;
public void setTimeToLive(Duration timeToLive) {
    this.timeToLive = timeToLive;
}


@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
    RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

    //解决查询缓存转换异常的问题
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);

    // 配置序列化(解决乱码的问题)
    RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(timeToLive)
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
            .disableCachingNullValues();

    RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
            .cacheDefaults(config)
            .build();
    return cacheManager;
}



}

自己设置主键规则

    @Configuration
public class CacheConfig {

@Bean("myKeyGenerator")
public KeyGenerator keyGenerator(){
    return new KeyGenerator() {
        @Override
        public Object generate(Object o, Method method, Object... objects) {
            return method.getName()+'['+ Arrays.asList(objects)+']';
        }
    };
}
}

5.一些基本使用

@SpringBootTest
class Spring01DataApplicationTests {

@Autowired
TestController testController;

@Autowired
DataSource dataSource;

@Autowired
StringRedisTemplate stringRedisTemplate;

@Autowired
RedisTemplate redisTemplate;

@Autowired
RedisTemplate<Object, testDomain> testRedisTemplate;

@Test
public void test01(){
    //操作字符串的
    //stringRedisTemplate.opsForValue().append("msg","hello");
    //System.out.println(stringRedisTemplate.opsForValue().get("msg"));
    //操作列表的
    stringRedisTemplate.opsForList().leftPush("myList", "1");
    stringRedisTemplate.opsForList().leftPush("myList", "2");
}

@Test
public void test02(){
    testDomain domain = new testDomain();
    //默认保存对象是序列化的效果
    redisTemplate.opsForValue().set("myObject",domain);
}

@Test
public void test03(){
    testDomain domain = new testDomain();
    //默认保存对象是序列化的效果
    testRedisTemplate.opsForValue().set("myObject2",domain);
}


@Test
void contextLoads() throws SQLException {
    System.out.println(testController.insert());
}

}

cacheManager配置

@Configuration
@ConfigurationProperties(prefix = "spring.cache.redis")
public class RedisCacheConfig {

private Duration timeToLive = Duration.ZERO;
public void setTimeToLive(Duration timeToLive) {
    this.timeToLive = timeToLive;
}

@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
    RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

    //解决查询缓存转换异常的问题
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);

    // 配置序列化(解决乱码的问题)
    RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(timeToLive)
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
            .disableCachingNullValues();

    RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
            .cacheDefaults(config)
            .build();
    return cacheManager;
}

}

消息服务

在应用中引入消息服务中间件提升系统异步通讯能力
消息服务两个重要概念消息代理(message broker)和目的地
方式:
点对点:消息只能有唯一的接受者和发送者,但并不是只能有一个接收者
发布订阅:发送者发送消息到主题,多个接收者监听这个主题,那么就会在消息到达时同时接受到这个消息
JMS:是java基于JVM的消息规范
AMQP:高级消息队列协议,是一个消息代理的规范,兼容JMS
Message:消息,消息是不具名的,他由消息头和消息体组成。
publisher:消息的生产者,也是一个向交换器发布消息的客户端应用程序
exchange:交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列
Queue:消息队列,用来保存消息知道发送给消费者
Binding:绑定,用于消息队列和交换器之间的关联。绑定就是基于路由键将交换器和消息队列连接起来的路由规则,可以将交换器理解成一个由绑定构成的路由表。
Connection:网络连接
Channel:信道,多路复用连接中的一条独立的双向数据流通表。
Consumer:消费者
Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务域。
Broker:表示消息队列服务器实体。
Excahge类型:
direct:直连型
fanout:广播模式
topic:对路由建进行模糊匹配,#0个或者多个单词,*匹配一个单词

在docker中下载rabbitmq

  docker pull rabbitmq:3-management

在docker中创建rabbitmq

docker run -d ---name  myrabbit -p 5672:5672 -p 15672:15672 a64a4ae7bc1f

rabbitmq
1、RabbitAutoConfiguration
2、有自动配置连接工厂ConnectionFactory
3、RabbitProperties封装了RabbitMQ的配置
4、RabbitTemple:给RabbitMQ发送和接受配置
5、AmqpAdmin:RabbitMQ系统管理功能组件

pom文件

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

application.yml

spring:
     rabbitmq:
        host: 207.148.95.94
        username: guest
        password: guest

测试类

  @SpringBootTest
class SpringAmqpApplicationTests {

@Autowired
RabbitTemplate rabbitTemplate;

@Test
void contextLoads() {
    //HashMap<String, String> map = new HashMap<>();
    //map.put("hello","hello2");
    rabbitTemplate.convertAndSend("exchange.direct","zheng",new Book("浩",55));
}

@Test
public void test01(){
    Object o = rabbitTemplate.receiveAndConvert("zheng");
    System.out.println(o.getClass());
    System.out.println(o);
}



}

Message序列化配置

@Configuration
public class MyConfigAMQP {

@Bean
public MessageConverter messageConverter(){
    return new Jackson2JsonMessageConverter();
}
}

队列监听器

@Service
public class BookService {
//    @RabbitListener( queues = "zheng")
//    public void receive(Book book){
//        System.out.println("收到消息:"+book);
//    }


@RabbitListener( queues = "zheng")
public void receive2(Message message){
    System.out.println(message.getBody() +"++++++++"+ message.getMessageProperties());
}


}

主配置文件

@EnableRabbit//开启rabbit注解
@SpringBootApplication
public class SpringAmqpApplication {

public static void main(String[] args) {
    SpringApplication.run(SpringAmqpApplication.class, args);
}

}

ElasticSearch添加检索功能,提供了Restful API,底层基于Lucene,采用shard方式保证了数据安全。

在docker中创建elasticsearch

拉取镜像

  docker pull elasticsearch:5.6.8

启动容器

   docker run --name my_es -d -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -p 9200:9200 -p 9300:9300 docker.io/elasticsearch:5.6.8

查看容器境况

docker ps

添加数据

官方文档

https://www.elastic.co/guide/cn/elasticsearch/guide/current/_indexing_employee_documents.html

发送PUT请求

http://207.148.95.94:9200/test/employee/1

body

{
"first_name" : "John",
"last_name" :  "Smith",
"age" :        26,
"about" :      "I love to go rock climbing",
"interests": [ "sports", "music" ]
}

使用GET请求得到检索

  http://207.148.95.94:9200/test/employee/_search

springboot默认支持两种技术来和ES交互

1、Jest(默认不生效,需要导入JEST工具包)
2、SpringBoot ElasticSearch
1)、Elasticsearch操作es
2)、ElasticsearchRepository的子接口操作ES

出现问题9200能打开,9300不能打开

异步的使用

在主程序中

@SpringBootApplication
@EnableAsync//开启异步注解
public class ElasticsearchApplication {

public static void main(String[] args) {
    SpringApplication.run(ElasticsearchApplication.class, args);
}

}

在业务层使用

@Service
public class HelloService {

@Async
public void hello() {
    try {
        Thread.sleep(Long.parseLong("3000"));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("处理数据");
}
}

控制层

@RestController
public class HelloController {

@Autowired
HelloService service;

@GetMapping("hello")
public String Hello(){
     service.hello();
    return "hello";
}
}

定时任务

主配置文件

@SpringBootApplication
@EnableScheduling//开启定时任务
public class ElasticsearchApplication {

public static void main(String[] args) {
    SpringApplication.run(ElasticsearchApplication.class, args);
}

}

实例

@Service
public class ScheduleService {

//second,minute,hour,day of month,month,day of week
@Scheduled(cron = "0 * * * *  MON-SAT")
public void hello(){
    System.out.println("zzzz");
}
}

邮件

pom文件依赖

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

配置文件

  spring:
      mail:
      password: qwwcmljtmxxzchbh
      username: xxxxxx@qq.com
      host: smtp.qq.com
          properties:
            mail:
              smtp:
                ssl:
                  enable: true

测试使用

@SpringBootTest
class ElasticsearchApplicationTests {

@Autowired
JavaMailSenderImpl sender;

@Test
void contextLoads() {
    SimpleMailMessage message = new SimpleMailMessage();
    message.setSubject("测试");
    message.setText("success");
    message.setTo("1071877529@qq.com");
    message.setFrom("3479554785@qq.com");
    sender.send(message);
}

//复杂的消息邮件
@Test
void contextLoads2() throws Exception {

    MimeMessage mimeMessage = sender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
    helper.setSubject("测试");
    helper.setText("<b>success2</b>",true);
    helper.setTo("1071877529@qq.com");
    helper.setFrom("3479554785@qq.com");
    helper.addAttachment("zheng.jpg",new File("D:\\myproject\\elasticsearch\\src\\main\\resources\\截图.PNG"));
    sender.send(mimeMessage);
}

}

安全

认证(认证自己的身份)和授权(你能干什么)

第一步导入依赖

  <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    </dependency>

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

第二步 编写密码编码

@Component
public class PasswordEncoder implements  org.springframework.security.crypto.password.PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
    return charSequence.toString();
}

@Override
public boolean matches(CharSequence charSequence, String s) {
    return s.equals(charSequence);
}
}

第三步,编写配置类

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
    //super.configure(http);
    //定制请求的授权规则
    http.authorizeRequests().antMatchers("/").permitAll()
            .antMatchers("/level1/**").hasRole("VIP1")
            .antMatchers("/level2/**").hasRole("VIP2")
            .antMatchers("level3").hasRole("VIP3");
    //开启自动配置登陆功能
    //1、/login来到登陆页面
    //2、重定向到/login?error来到错误页面
    http.formLogin().usernameParameter("user").passwordParameter("pwd").loginPage("/userlogin");
    //开启自动配置的注销
    http.logout().logoutSuccessUrl("/");

    //记住账号密码
    http.rememberMe();
}

//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //super.configure(auth);
    auth.inMemoryAuthentication().passwordEncoder(new PasswordEncoder()).withUser("zheng").password("123456")
            .roles("VIP1","VIP2")
            .and().withUser("hao").password("hao")
            .roles("VIP3","VIP2");
}
}

第四步,编写控制类

@Controller
public class TestController {

private final String preffix = "/pages/";

@GetMapping("/")
public String index(){
    return "welcome";
}

@GetMapping("/level1/{path}")
public String level1(@PathVariable("path")String path){
    return preffix+"level1/path"+path;
}

@GetMapping("/level2/{path}")
public String level2(@PathVariable("path")String path){
    return preffix+"level2/path"+path;
}

@GetMapping("/level3/{path}")
public String level3(@PathVariable("path")String path){
    return preffix+"level3/path"+path;
}


@GetMapping("/userlogin")
public String login(){
    return preffix+"login/login";
}
}

欢迎页面

<!DOCTYPE html>
  <html xmlns:th="http://www.thymeleaf.org"
  xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 align="center">欢迎光临武林秘籍管理系统</h1>
<div sec:authorize="!isAuthenticated()">
<h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/userlogin}">请登录</a></h2>
</div>
<div sec:authorize="isAuthenticated()">
<h2><span sec:authentication="name"></span>,您好,您的角色有:
    <span sec:authentication="principal.authorities"></span></h2>
<form th:action="@{/logout}" method="post">
    <input type="submit" value="注销"/>
</form>
</div>

<hr>

<div sec:authorize="hasRole('VIP1')">
<h3>普通武功秘籍</h3>
<ul>
    <li><a th:href="@{/level1/1}">罗汉拳</a></li>
    <li><a th:href="@{/level1/2}">武当长拳</a></li>
    <li><a th:href="@{/level1/3}">全真剑法</a></li>
</ul>

</div>

<div sec:authorize="hasRole('VIP2')">
<h3>高级武功秘籍</h3>
<ul>
    <li><a th:href="@{/level2/1}">太极拳</a></li>
    <li><a th:href="@{/level2/2}">七伤拳</a></li>
    <li><a th:href="@{/level2/3}">梯云纵</a></li>
</ul>

</div>

<div sec:authorize="hasRole('VIP3')">
<h3>绝世武功秘籍</h3>
<ul>
    <li><a th:href="@{/level3/1}">葵花宝典</a></li>
    <li><a th:href="@{/level3/2}">龟派气功</a></li>
    <li><a th:href="@{/level3/3}">独孤九剑</a></li>
</ul>
</div>


</body>
</html>

注册页面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 align="center">欢迎登陆武林秘籍管理系统</h1>
<hr>
<div align="center">
    <form th:action="@{/userlogin}" method="post">
        用户名:<input name="user"/><br>
        密码:<input name="pwd"><br/>
        <input type="checkbox" name="remeber"> 记住我<br/>
        <input type="submit" value="登陆">
    </form>
</div>
</body>
</html>

SpringBoot分布式

在分布式中国内常见的是ZooKeeper + Dubbo,SpringBoot推荐使用全栈的Spring Boot + Spring Cloud

ZooKeeper是一个分布式的,开源的分布式应用程序协调服务。用作注册中心。
Dubbo:Dubbo是Alibaba开源的分布式服务框架,他最大的特点就是按照分层的方式来架构,使用这种方式可以使各个层之间解耦,可以作为消费者和提供者。

docker run --name my_zk -p 2181:2181 --restart always -d zookeeper

使用dubbo
1.将服务提供者注册到注册中心
1、引入dubbo和zkclient相关依赖

2、配置dubbo的扫描包和注册中心地址

3、使用dubbo的@Service发布服务

出现问题注意

消费者使用

1、引入依赖
2、配置dubbo注册中心
3、引用服务

SpringCloud是一个解决分布式的整体方案。
五大组件
Netflix Eureka --服务发现
Netflix Ribbon——服务端负载均衡
Netflix Hystrix——断路器
Netflix Zuul——服务网关
Spring Cloud Config——分布式配置

热部署

      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>

Crtl+F9

上一篇下一篇

猜你喜欢

热点阅读