dubbo+springboot项目

系统间通信问题

数据同步

在这里插入图片描述
性能有影响。有新的系统,代码需要更新,耦合太高。
方案二:引入消息中间件(MQ),可解耦,异步化。
在这里插入图片描述

RabbitMQ

1、simple模式:一对一
在这里插入图片描述
2、work模式:消息是共享模式

在这里插入图片描述
限流:对于消费者说,哪个干的快,哪个就干的多。给1个,处理完后再给下一个。
用限流+手工确认。
3、发布订阅模式

在这里插入图片描述
X:交换机,有两个队列,每个消费者都有队列。
生产者面向的是交换机。
4、路由模式:可以指定推送消息给消费者。打标记。
5、通配符模式:
在这里插入图片描述
*

采用MQ的场景

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

邮件服务

redis实战

首页使用redis优化

第一次没有查数据库,第二次就不用查数据库,可以直接查缓存。
在这里插入图片描述
在这里插入图片描述

  • 配置application.yml
redis:
    host: 192.168.142.137
    port: 6379
    password: java1907
  • 配置类redisConfig
@Configuration
public class RedisConfig {

    @Bean(name = "myStringRedisTemplate")
    public RedisTemplate<String,Object> getRedisTemplate(RedisConnectionFactory connectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());

        return redisTemplate;
    }
}

建一个RedisTemplate的对象

  • service实现
@Service
public class ProductTypeServiceImpl extends BaseServiceImpl<TProductType> implements IProductTypeService {

    @Autowired
    private TProductTypeMapper productTypeMapper;

    @Resource(name = "myStringRedisTemplate")
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    public IBaseDao<TProductType> getBaseDao() {
        return productTypeMapper;
    }

    /**
     * 重写获取列表的方法,加入缓存的逻辑
     * 硬件
     * 内存读取速度》磁盘读取速度
     * @return
     */
    @Override
    public List<TProductType> list() {
        //1.查询当前缓存是否存在分类信息
        List<TProductType> list = (List<TProductType>) redisTemplate.opsForValue().get("productType:list");
        if (list == null || list.size()==0) {
            //2.缓存不存在,则查询数据库
            list = super.list();
            //3.将查询结果保存到缓存中
            redisTemplate.opsForValue().set("productType:list",list);
        }
        return list;
    }
}
  • Controller层调用
@Controller
@RequestMapping("index")
public class IndexController {

    @Reference
    private IProductTypeService productTypeService;

    @RequestMapping("show")
    public String showIndex(Model model) {
        //1.获取到数据
        List<TProductType> list = productTypeService.list();
        //2.传递到前端进行展示
        model.addAttribute("list", list);
        //
        return "index";
    }

    @RequestMapping("listType")
    @ResponseBody
    public ResultBean listType() {
        //1.获取到数据
        List<TProductType> list = productTypeService.list();
        //2.封装返回
        return new ResultBean("200", list);
    }
}

首页展示是远程调用了商品服务

注册系统

注册系统是远程调用了用户的服务
在这里插入图片描述
通过MQ去异步通知邮件服务进行邮件发送。

Mq应用场景:发送邮件
在这里插入图片描述
在这里插入图片描述
发送失败怎么处理?
在这里插入图片描述

登录系统

表结构设计

表名:t-user
在这里插入图片描述
phone和email加唯一索引
在这里插入图片描述
统一定义返回:ResultBean
在这里插入图片描述

@Data
@AllArgsConstructor
public class ResultBean<T> implements Serializable{

    private String statusCode;
    private T data;

}

用户类:

public class TUser implements Serializable{
    private Long id;

    private String username;

    private String password;

    private String phone;

    private String email;

    private Boolean flag;

    private Date createTime;

    private Date updateTime;
    }
  • 接口层
    IUserService:
    在这里插入图片描述
public interface IUserService extends IBaseService<TUser>{
    public ResultBean checkUserNameIsExists(String username);
    public ResultBean checkPhoneIsExists(String phone);
    public ResultBean checkEmailIsExists(String email);
    public ResultBean generateCode(String identification);
    ResultBean checkLogin(TUser user);
    ResultBean checkIsLogin(String uuid);
  • service层:
    在这里插入图片描述
@Service
public class UserServiceImpl extends BaseServiceImpl<TUser> implements IUserService{

    @Autowired
    private TUserMapper userMapper;

    @Resource(name = "myStringRedisTemplate")
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public ResultBean checkUserNameIsExists(String username) {
        return null;
    }

    @Override
    public ResultBean checkPhoneIsExists(String phone) {
        return null;
    }

    @Override
    public ResultBean checkEmailIsExists(String email) {
        return null;
    }

    @Override
    public ResultBean generateCode(String identification) {
        //1.生成验证码
        String code = CodeUtils.generateCode(6);
        //2.往redis保存一个凭证跟验证码的对应关系 key-value
        redisTemplate.opsForValue().set(identification,code,2, TimeUnit.MINUTES);
        //3.发送消息,给手机发送验证码
        //3.1 调通阿里云提供的短信Demo
        //3.2 发送短信这个功能,整个体系很多系统都可能会用上,变成一个公共的服务
        //3.3 发送消息,异步处理发送短信
        Map<String,String> params = new HashMap<>();
        params.put("identification",identification);
        params.put("code",code);
        rabbitTemplate.convertAndSend("sms-exchange","sms.code",params);

        //此处是不需要发送任何邮件,仅做测试使用
        Map<String,String> params2 = new HashMap<>();
        params2.put("to","2678383176@qq.com");
        params2.put("username","马老师");

        rabbitTemplate.convertAndSend("email-exchange","email.birthday",params2);

        return new ResultBean("200","OK");
    }

    @Override
    public ResultBean checkLogin(TUser user) {
        //1.根据用户输入的账号(手机/邮箱)信息,去查询
        TUser currentUser = userMapper.selectByIdentification(user.getUsername());
        //2.根据查询出来的密码信息,进行比较
        if(currentUser != null){
            //if(user.getPassword().equals(currentUser.getPassword())){
            if(passwordEncoder.matches(user.getPassword(),currentUser.getPassword())){
                //1.生成uuid
                //String uuid = UUID.randomUUID().toString();
                //2.保存到redis中,并设置有效期为30分钟,代替原先的session
                //redisTemplate.opsForValue().set("user:token:"+uuid,currentUser.getUsername(),30,TimeUnit.MINUTES);

                //生成令牌
                JwtUtils jwtUtils = new JwtUtils();
                jwtUtils.setSecretKey("java1907");
                jwtUtils.setTtl(30*60*1000);

                String jwtToken = jwtUtils.createJwtToken(currentUser.getId().toString(), currentUser.getUsername());

                //TODO 构建一个map,返回令牌和唯一标识
                Map<String,String> params = new HashMap<>();
                params.put("jwttoken",jwtToken);
                params.put("username",currentUser.getUsername());

                return new ResultBean("200",params);
            }
        }
        return new ResultBean("404",null);
    }

    @Override
    public ResultBean checkIsLogin(String uuid) {
        //1.拼接key
        //StringBuilder key = new StringBuilder("user:token:").append(uuid);
        //2.查询redis
        //String username = (String) redisTemplate.opsForValue().get(key.toString());
        //3.返回结果
        /*if(username != null){
            //刷新凭证的有效期
            redisTemplate.expire(key.toString(),30,TimeUnit.MINUTES);
            //
            return new ResultBean("200",username);
        }*/
        JwtUtils jwtUtils = new JwtUtils();
        jwtUtils.setSecretKey("java1907");

        //ExpiredJwtException
        //RuntimeException
        //解析令牌
        try {
            Claims claims = jwtUtils.parseJwtToken(uuid);
            String username = claims.getSubject();
            return new ResultBean("200",username);
        }catch (RuntimeException ex){
            //如果针对不同的异常,我们需要区分对待,那么就应该写多个catch,分别处理
            //如果是一样的处理方式,那么直接统一就行
            return new ResultBean("404",null);
        }
    }

    @Override
    public IBaseDao<TUser> getBaseDao() {
        return userMapper;
    }
}
  • Controller层
    在这里插入图片描述
@Controller
@RequestMapping("user")
public class UserController {

    @Reference
    private IUserService userService;

    @GetMapping("checkUserNameIsExists/{username}")
    @ResponseBody
    public ResultBean checkUserNameIsExists(@PathVariable("username") String username){
        return userService.checkUserNameIsExists(username);
    }

    @GetMapping("checkPhoneIsExists/{phone}")
    @ResponseBody
    public ResultBean checkPhoneIsExists(@PathVariable("phone") String phone){
        return userService.checkPhoneIsExists(phone);
    }

    @GetMapping("checkEmailIsExists/{email}")
    @ResponseBody
    public ResultBean checkEmailIsExists(@PathVariable("email") String email){
        return userService.checkEmailIsExists(email);
    }

    @PostMapping("generateCode/{identification}")
    @ResponseBody
    public ResultBean generateCode(@PathVariable("identification") String identification){
        return userService.generateCode(identification);
    }

    /**
     * 适合处理异步请求
     * @return
     */
    @PostMapping("register")
    @ResponseBody
    public ResultBean register(TUser user){
        return null;
    }

    /**
     * 适合处理同步请求,跳转到相关页面
     * @return
     */
    @PostMapping("register4PC")
    public String register4PC(TUser user){
        return null;
    }

    @GetMapping("activating")
    public String activating(String token){
        return null;
    }


在这里插入图片描述

  1. 需要设计的接口

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

关键点,系统是如何为用户保存登录凭证的?

在这里插入图片描述

基于session操作

简单的登录验证:
在这里插入图片描述
简单验证用户是否登录:
在这里插入图片描述简单的注销:
在这里插入图片描述
问题:微服务架构下还能适用吗?
分布式拆分,集群保证高可用,session不能共享
在这里插入图片描述
探讨解决方案:
通过cookie解决
在这里插入图片描述
jsessionId:凭证信息
2.是http协议的特性,1.是服务器自动的行为
在这里插入图片描述有状态的解决方案:

在这里插入图片描述

代码层面

登录校验

  • 增加redis依赖
    1、登录验证,生成uuid,并保存在redis中

service层

public ResultBean checkLogin(TUser user) {
        //1.根据用户输入的账号(手机/邮箱)信息,去查询
        TUser currentUser = userMapper.selectByIdentification(user.getUsername());
        //2.根据查询出来的密码信息,进行比较
        if(currentUser != null){
            //if(user.getPassword().equals(currentUser.getPassword())){
            if(passwordEncoder.matches(user.getPassword(),currentUser.getPassword())){
                //1.生成uuid
                String uuid = UUID.randomUUID().toString();
                //2.保存到redis中,并设置有效期为30分钟,代替原先的session
 redisTemplate.opsForValue().set("user:token:"+uuid,currentUser.getUsername(),30,TimeUnit.MINUTES);
                   return new ResultBean("200",uuid);
            }
        }
        return new ResultBean("404",null);
    }

redis的key值:“user:token:”+uuid,保证唯一性
redis的value值:currentUser.getUsername(),当前用户的名字

  • SSOController层
 @PostMapping("checkLogin")
    @ResponseBody
    public ResultBean checkLogin(TUser user,HttpServletResponse response){
        ResultBean resultBean = userService.checkLogin(user);
        //2.如果正确,则在服务端保存凭证信息
        if("200".equals(resultBean.getStatusCode())){
            //TODO 写cookie给客户端,保存凭证
            //1.获取uuid
            String uuid = (String) resultBean.getData();
            //2.创建cookie对象
            Cookie cookie = new Cookie("user_token",uuid);
            cookie.setPath("/");
            //设置cookie的域名为父域名,这样所有子域名系统都可以访问该cookie,解决cookie的跨域问题
            cookie.setDomain("qf.com");
            cookie.setHttpOnly(true);
            //3.写cookie到客户端
            response.addCookie(cookie);
        }
        return resultBean;
    }

resultBean里返回了uuid,并且在userservice服务中这个值,已经被写入了redis。
如何将cookie写入到客户端,使用返回对象,response.addCookie();

校验是否在登录状态
1、获取cookie,获取user_token的值,在请求头里,所以用request去取
2、去redis中查询,是否存在这个凭证
SSOController层

在这里插入图片描述

@GetMapping("checkIsLogin")
    @CrossOrigin(origins = "*",allowCredentials = "true")
    @ResponseBody
    public ResultBean checkIsLogin(@CookieValue(name = "user_token",required = false) String uuid){
        //1.获取cookie,获取user_token的值
        if(uuid != null){
            //2.去redis中查询,是否存在该凭证信息
            ResultBean resultBean = userService.checkIsLogin(uuid);
            return resultBean;
        }
        return new ResultBean("404",null);
    }

service层

@Override
    public ResultBean checkIsLogin(String uuid) {
        //1.拼接key
        StringBuilder key = new StringBuilder("user:token:").append(uuid);
        //2.查询redis
        String username = (String) redisTemplate.opsForValue().get(key.toString());
        ///3.返回结果
        if(username != null){
            //刷新凭证的有效期
            redisTemplate.expire(key.toString(),30,TimeUnit.MINUTES);
            
            return new ResultBean("200",username);
        }
       
    }

一旦有操作,要刷新redis凭证的有效期,如果有,那就刷新继续持续30min

redisTemplate.expire(key.toString(),30,TimeUnit.MINUTES)

具体的实现,是远程调用service层下面的userservice服务
回顾梳理:
在这里插入图片描述
在service层中通过checkLogin方法,去生成一个cookie凭证,并保存在redis中,设置超时时间30min;
然后Controller层中,将cookie写入到客户端。
当做登录验证时,调用checkLogin,返回一个resultBean,Bean里有redis中存入的凭证,如果验证通过了,将凭证(cookie),通过response.addCookie(cookie),写入到客户端。
**

全文索引的实现

**

搭建solar服务器

安装IK分词解释器

在这里插入图片描述

springboot整合solr

在这里插入图片描述
与自定义域的索引保持一致。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

查询和删除

在这里插入图片描述
在这里插入图片描述
精确匹配用id;

全量同步数据

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个开源的Java框架,用于快速构建独立的、基于Spring的应用程序。它简化了Spring应用程序的配置和部署过程,并提供了许多嵌入式服务器,如Tomcat、Jetty等。Spring Boot还提供了自动配置的特性,可以根据类路径中的依赖自动配置Spring应用程序。 Dubbo是一款高性能的分布式服务框架,也是阿里巴巴开源的项目。它提供了服务治理、远程通讯和分布式调用等功能,帮助开发人员轻松构建分布式服务化的应用。 Zookeeper是一个开源的分布式协调服务,可以用于实现分布式应用程序的一致性和可靠性。它提供了一个类似于文件系统的层次化的命名空间,并允许开发人员注册、协调和共享各种资源,如配置信息、服务注册和发现等。 当使用Spring Boot结合Dubbo和Zookeeper时,可以构建一个高性能、可扩展和可靠的微服务架构。Spring Boot提供了便利的开发和部署方式,Dubbo提供了分布式服务框架的支持,而Zookeeper则提供了分布式协调服务。开发人员可以使用Spring Boot快速构建独立的微服务应用程序,使用Dubbo进行服务间的通信和管理,同时通过Zookeeper进行服务的注册和发现。这样的架构可以方便地实现微服务架构中的资源共享和服务治理等功能,大大简化了开发人员的负担。 综上所述,Spring Boot结合Dubbo和Zookeeper可以构建高效、可靠的微服务架构,并提供了便利的开发和部署方式,帮助开发人员构建高性能的分布式应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值