美文网首页
SpringBoot

SpringBoot

作者: dillqq | 来源:发表于2020-02-14 17:48 被阅读0次

    @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

    相关文章

      网友评论

          本文标题:SpringBoot

          本文链接:https://www.haomeiwen.com/subject/tzmxxhtx.html