Springboot+Redis+dubbo+zookeeper整合

Springboot+Redis+dubbo+zookeeper

一、Springboot+Redis整合

  1. 导入依赖(直接导入nosql中的redis)
<!--操作redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 配置连接
# 本地redis测试
spring.redis.host=127.0.0.1
spring.redis.port=6379
#新版本使用lettuce(线程安全)
spring.redis.lettuce.pool.max-active=8
#jedis已近失效---不使用
spring.redis.jedis.pool.max-active=8
  1. 测试
@Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        // opsForValue操作字符串
        redisTemplate.opsForValue().set("lsx","carters123456");
        System.out.println(redisTemplate.opsForValue().get("lsx"));
    }
  1. 实际开发中自己定义RedisTemplate

添加依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.73</version>
</dependency>

实体类

@Component // 变成组件
@AllArgsConstructor// 有参数
@NoArgsConstructor// 无参数
@Data
// 企业中需要序列化
public class User implements Serializable {
    private String name;
    private int age;
}

操作

@Test
    void test() {
        // 真实项目中
        User user = new User("廖述幸", 3);
        // 对象序列化
        String jsonUser = JSONObject.toJSONString(user);
        redisTemplate.opsForValue().set("user",jsonUser);
        System.out.println(redisTemplate.opsForValue().get("user"));
    }

输出结果:{“age”:3,“name”:“廖述幸”}

  1. 自定义Redistemplate

添加依赖

<!--ObjectMapper的依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

配置RedistemplateConfig

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.net.UnknownHostException;

@Configuration
public class RedisConfig {
    // 企业中固定模板
    // 编写我们自己的 redisTemplate
    // <bean id=方法名:redisTemplate class=返回值:RedisTemplate
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory)
            throws UnknownHostException {
        // 1、默认设置,为了开发方便使用String + Object
        RedisTemplate<String, Object> template = new RedisTemplate<>();

        // 2、连接工厂
        template.setConnectionFactory(factory);

        // 3、json序列化的配置

        // jackson解析任意对象
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 4、String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // key统一采用String填写
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也用String填写
        template.setHashKeySerializer(stringRedisSerializer);

        // value的序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式也采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        template.afterPropertiesSet();
        return template;
    }
}

使用自己的RedisTemplate

@Autowired
@Qualifier("redisTemplate")// 使用id进行定义,防止未生效
private RedisTemplate redisTemplate;

@Test
void test() {
    // 真实项目中 (自己定义的redisTemplate)
    User user = new User("廖述幸", 3);
    redisTemplate.opsForValue().set("user",user);
    System.out.println(redisTemplate.opsForValue().get("user"));
}

输出结果:User(name=廖述幸, age=3)

  • 与未定义时候的区别

在这里插入图片描述

二、Springboot+bubbo整合

分布式:一个人只用一台机,为啥考虑多台机?


RPC:通信 和 序列化 核心模块

  1. 下载 dubbo-admin后台管理

https://github.com/apache/dubbo-admin/tree/master

  1. 解压+在项目目录下打包dubbo-admin

mvn clean package -Dmaven.test.skip=true

打成一个jar包,可以直接运行【D:\Environment\java-linux\dubbo-admin-master\dubbo-admin\target目录下的jar】

  1. 下载zookeeper,在windows下运行

找到bin目录下----copy得到zoo.cfg

编辑zkServer.cmd 在最后面输入 pause,报错不是闪退而是展示错误

  • 代码部分
  1. 建立一个空的项目
  2. 建立一个新的moudel—>provider-server的springboot项目+web依赖
  3. 建立另一个一个新的moudel—>cunsumer-server的springboot项目+web依赖

添加dubbo+zookeeper依赖

<!--Dubbo依赖 最新版 许多冲突需要进行排查-->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.8</version>
</dependency>

<!--zkClient客户端依赖-->
<dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.1</version>
    <!--解决日志和zookeeper冲突-->
    <exclusions>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!--日志冲突-->
<!--zookeeper依赖-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>5.1.0</version>
    <exclusions>
        <!--解决与zookeeper的依赖冲突-->
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <!--3.6.0版本避免zookeeper与curator-framework依赖冲突-->
    <version>3.6.1</version>
    <!--排除日志冲突-->
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

application.properties配置

provider-server配置

# 应用服务 WEB 访问端口
server.port=8001

# 服务应用的名字
dubbo.application.name=provider-server
# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 哪些服务需要注册
dubbo.scan.base-packages=com.carter.service

cunsumer-server配置

# 应用服务 WEB 访问端口
server.port=8002
# 暴露自己的名字
dubbo.application.name=cunsumer-server
# 注册中心地址 哪里拿  远程改成远程
dubbo.registry.address=zookeeper://127.0.0.1:2181

接口com.carter.service的HelloService代码实现

public interface HelloService {
    public String sayHello(String name);
}

接口实现类HelloServiceImpl

// 服务注册与发现
@Service// 可以被扫描到,在项目启动就可以注册到注册中心
@Component // 使用了dubbo后尽量不要用@Service进行注解
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
        return "hello "+name;
    }
}
  • 进行远程连接
  1. 打开zkService
  2. 开启dubbo-admin
  3. 启动provider-server
  4. 登录 http://localhost:7001/进行注册中心查看

在这里插入图片描述

三、springboot+SpringSecurity整合

1、登录功能

导入依赖

<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

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

<!--fastjson-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.73</version>
</dependency>

<!--thymeleaf+springSecurity整合包-->
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>

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

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

<!--thymeleaf模板 start-->
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<!--thymeleaf模板 end-->

代码实现

  1. 增加一个MyDetailUser的实体类

    import lombok.Data;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    
    import java.util.Collection;
    
    @Data
    public class MyDetailUser extends User {
        private String phone; //手机号码(附赠品牌)
        public MyDetailUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
            super(username, password, authorities);
        } //构造方法username:账户 password密码 authorities权限
    }
    
  2. 增加一个UserDetailServiceImpl实现方法

import com.carter.dao.UserDao;
import com.carter.pojo.MyDetailUser;
import com.carter.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    private UserDao userDao;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userDao.selectUserByUsername(username); //userDao中根据username查询整个user对象的方法
        List<String> roleNameList; //根据user_id得到的权限集合
        MyDetailUser detailUser = null; //springSecurity中的User自定义对象
        List<SimpleGrantedAuthority> authorityList = new ArrayList<>(); //权限集合
        if (user!=null){
            roleNameList = userDao.selectRoleNameByUserId(user.getId()); //根据user_id得到对应的role_name权限集合
            for (String roles : roleNameList) { //循环遍历User对应的所有权限
                System.out.println("权限为--->"+roles); //进行输出打印
                authorityList.add(new SimpleGrantedAuthority("ROLE_"+roles)); //ROLE_时必须添加的,将权限添加到springSecurity权限集合中
            }
            detailUser = new MyDetailUser(username, user.getPassword(), authorityList);
            detailUser.setPhone("17369284516"); //根据情况进行springSecurity中User对象的改变
        }
        return detailUser;
    }
}
  1. SecurityConfig中进行调用
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 SecurityConfig extends WebSecurityConfigurerAdapter {

    // 授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 定义规则 首页所有人能访问,功能也只有权限的人才能访问
         * 请求授权的规则
         * 表示以/level1/开头的url请求 只有vip1权限才能访问
         * 强行执行【type=Forbidden禁止的, status=403】,报错
         */
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        /**
         * 强行执行(没有权限)--->登录界面  http.formLogin()【默认】
         * loginPage("/toLogin")【定制登录页面】
         * 登录提交时候我们就要走login,而不是和loginPage的参数一样必须toLogin
         * loginProcessingUrl("/login")定义提交的时候可以用login
         * loginProcessingUrl = validate username and password 【必须是username和password才能接受表单数据】
         * .usernameParameter("web表单中账户定义的name")【看源码】
         */
        http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password");

        /**
         * 防止网站攻击:get注销不安全,【403错误】
         * 关闭跨站防攻击
         */
        http.csrf().disable();

        /**
         * 注销功能+清空Cookies 【.deleteCookies("remove").invalidateHttpSession(true)】
         * 回到首页url
         */
        http.logout().logoutSuccessUrl("/");

        /**
         * 开启记住我功能--->关闭浏览器任然存在【默认保存14天】
         * 自定义接受前端参数
         */
        http.rememberMe().rememberMeParameter("remember");
    }

    /**
     * 2:认证,springboot version2.0.7稳定 可以直接使用  【其他版本 type=Internal Server Error, status=500】500错误
     * 密码没有编码直接报错passwordEncoding
     *在springSecurity 5.0+ 新增了很多加密方法
     * passwordEncoder(new BCryptPasswordEncoder())加密方式
     */

    @Autowired
    private UserDetailServiceImpl userDetailService; //配置springSecurity中的User对象
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // ①内存中的身份验证
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("lsx").password(new BCryptPasswordEncoder().encode("1122")).roles("vip2","vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("1122")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("1122")).roles("vip1");
        
        //②数据库的认证方式---userDetailService调用
        auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder()); 
    }
}

前端主页

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<!--记得导入sec的命名空间-->
<head>
    <meta charset="UTF-8">
    <title>首页界面</title>
</head>
<body>
<div style="text-align: center;">
    <h3>欢迎来到首页</h3>
    <br><br>

    <div sec:authorize="hasRole('vip1')">
        <h4 style="color: red">Level1</h4>
        <a href="/level1/1">Level1-1</a>
        <a href="/level1/2">Level1-2</a>
        <a href="/level1/3">Level1-3</a>
        <br><br>
    </div>

    <div sec:authorize="hasRole('vip2')">
        <h4 style="color: green">Level2</h4>
        <a href="/level2/1">Level2-1</a>
        <a href="/level2/2">Level2-2</a>
        <a href="/level2/3">Level12-3</a>
        <br><br>
    </div>

    <div sec:authorize="hasRole('vip3')">
        <h4 style="color: blue">Level3</h4>
        <a href="/level3/1">Level3-1</a>
        <a href="/level3/2">Level3-2</a>
        <a href="/level3/3">Level3-3</a>
        <br><br>
    </div>

    <!--未登录显示登录-->
    <div sec:authorize="!isAuthenticated()">
        <a href="/toLogin">登录</a>
    </div>

    <!--登录显示注销+用户名-->
    <div sec:authorize="isAuthenticated()">
        <a>用户名:<span sec:authentication="name"></span></a>
        <br><br>
        手机号码:
        <span sec:authentication="principal.phone"/>

    </div>

    <!--登录显示注销-->
    <div sec:authorize="isAuthenticated()">
        <a href="/logout">注销</a>
    </div>
</div>
</body>
</html>
2、注册功能

RouterController注册时查询可以选择的用户权限

@RequestMapping("/toRegister") //跳转至注册界面
    public String toRegister(Model model){
        List<Role> roleList = roleService.queryRoles(); //查询可选择的所有用户权限
        model.addAttribute("roleList",roleList); //存到MOdel中
        return "views/register";
    }

前端register.html【html不支持EL表达式】

<html lang="en" xmlns:th="http://www.thymeleaf.org"> thymeleaf模板
<th colspan="2">
    权限选择
    <select name="roleId" id="roleId">
        <option th:each="role : ${roleList}" th:id="${role.id}" th:value="${role.id}" th:text="${role.roleName}"></option>
    </select>
</th>

在这里插入图片描述

Security配置登录失败跳转页面loginFailed

http.formLogin() //开启formLogin模式
                .loginPage("/toLogin") //用户未登陆时,访问任何资源都会跳转到改路径,即为登录页面
                .loginProcessingUrl("/login") //登录表单form中action的地址,也就是处理认证请求的路径
                .usernameParameter("username") //表单name对应的值,springSecurity默认是username
                .passwordParameter("password") //表单name对应的值,springSecurity默认是password
                .defaultSuccessUrl("/") //登录成功跳转接口
                .failureUrl("/loginFailed"); // 登陆失败跳转页面【默认跳转toLogin?error】

RouterController中的loginFailed方法

@RequestMapping("/loginFailed") //登录失败
    public String loginFailed(Model model){
        model.addAttribute("error","登录失败"); //登录失败提示信息
        return "views/login";
    }

四、springboot+shiro整合

五、聊一聊微服务

微服务架构问题?

分布式架构会遇到的4大核心问题?

		1. 这么多服务,客户端如何去访问? // 网关
        			2. 这么多服务,服务之间如何通信? // Fegin
              			3. 这么多服务如何治理?  // zookeepr
        			4. 服务挂了怎么办?   // 熔断机制

解决方案:

​ springcloud,是一套生态,解决以上4个分布式问题

  1. spring cloud NetFlix 一套解决方案 一站式解决方案

    ​ Api网关 zuul组件

    ​ Fegin ----> HTTPClient—> 基于HTTP通信方式,同步并阻塞

    ​ 服务注册与发现 —> Eureka

    ​ 熔断机制,Hystrix

    2018年年底,NetFlix宣布无限期停止维护。生态不再维护,就会脱节

  2. Apache Dubbo zookeeper 第二套解决系统

    Api:没有!!! 要么找第三方组件,要么自己实现

    Dubbo 是一个高性能的基于java实现的 RPC框架—>解决通信问题

    服务注册与发现,zookeeper:动物园管理者(hadoop,Hive)

    没有熔断机制!!!只能借助 Hystrix

  3. SpringCloud Alibaba 一站式解决方案

  4. 又提出了一种方案===服务网格(下一代微服务标准 Server Mesh

    解决方案:istio (未来可能需要掌握)

分布式架构会遇到的4大核心问题?

		1. 这么多服务,客户端如何去访问? // 网关
        			2. 这么多服务,服务之间如何通信? // Fegin
              			3. 这么多服务如何治理?  // zookeepr
        			4. 服务挂了怎么办?   // 熔断机制

解决方案:

​ springcloud,是一套生态,解决以上4个分布式问题

  1. spring cloud NetFlix 一套解决方案 一站式解决方案

    ​ Api网关 zuul组件

    ​ Fegin ----> HTTPClient—> 基于HTTP通信方式,同步并阻塞

    ​ 服务注册与发现 —> Eureka

    ​ 熔断机制,Hystrix

    2018年年底,NetFlix宣布无限期停止维护。生态不再维护,就会脱节

  2. Apache Dubbo zookeeper 第二套解决系统

    Api:没有!!! 要么找第三方组件,要么自己实现

    Dubbo 是一个高性能的基于java实现的 RPC框架—>解决通信问题

    服务注册与发现,zookeeper:动物园管理者(hadoop,Hive)

    没有熔断机制!!!只能借助 Hystrix

  3. SpringCloud Alibaba 一站式解决方案

  4. 又提出了一种方案===服务网格(下一代微服务标准 Server Mesh

    解决方案:istio (未来可能需要掌握)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值