当前位置: 首页 > news >正文

瑞吉外卖2.0 Redis 项目优化 Spring Cache MySQL主从复制 sharding-JDBC Nginx

Git版本控制

Linux从安装到实战&瑞吉外卖项目部署

Redis基础

Redis入门 redis.io

nosql没有表的概念

注意关闭防火墙

systemctl stop firewalld

启动redis

 src/redis-server ./redis.conf

数据类型

常用命令

字符串 string 操作命令

哈希 hash 操作命令

列表list(类似 栈 )操作命令

集合set 操作命令

sdiff key1 [key2] :key1-key2;

有序集合 sorted set (zset) 操作命令

通用命令

TTL return -1 表示永久;

在Java中操作Redis

介绍

Jedis

Spring Data Redis

Redis服务默认会给16个数据库在redis.windows.conf里面修改

默认是在0号数据库操作,更换数据库:select 1

String
hash
List
Set
ZSet
通用操作,针对不同数据类型都可以操作

项目优化-缓存优化

环境搭建

如何查看本地Ip

配置RedisConfig:为了自定义序列化器

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        //默认的Key序列化器为:JdkSerializationRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }
}

缓存短信验证码

保存方式:Session-->Redis

  @Autowired
    private RedisTemplate redisTemplate;
@PostMapping("/sendMsg")
    public R<String> sendMsg(@RequestBody User user, HttpSession session){
        String phone = user.getPhone();//获取手机号

        if(StringUtils.isNotEmpty(phone)){//手机号非空
            //工具类 生成随机的4位验证码
            String code = ValidateCodeUtils.generateValidateCode(4).toString();
            log.info("code={}",code);

            //调用阿里云提供的短信服务API("签名","模板",手机号,动态验证码)完成发送短信
            //SMSUtils.sendMessage("瑞吉外卖","",phone,code);
            //需要将生成的验证码保存到Session
            //session.setAttribute(phone,code);
            //将生成的验证码保存到Session
            redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES);

            return R.success("手机验证码短信发送成功");
        }
        return R.error("短信发送失败");
    }
@PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session){
        log.info(map.toString());
        //获取手机号
        String phone = map.get("phone").toString();
        //获取验证码
        String code = map.get("code").toString();

        //从Session中获取保存的验证码
        //Object codeInSession = session.getAttribute(phone);
        //从redis中获得缓存的验证码
        Object codeInSession = redisTemplate.opsForValue().get(phone);

        //进行验证码的比对(页面提交的验证码和Session中保存的验证码比对)
        if(codeInSession != null && codeInSession.equals(code)){
            //如果能够比对成功,说明登录成功
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone,phone);

            User user = userService.getOne(queryWrapper);
            if(user == null){
                //判断当前手机号对应的用户是否为新用户,如果是新用户就自动完成注册
                user = new User();
                user.setPhone(phone);
                user.setStatus(1);
                userService.save(user);
            }
            session.setAttribute("user",user.getId());
            //如果用户登录成功,删除redis中缓存的验证码
            redisTemplate.delete(phone);
            return R.success(user);
        }
        return R.error("登录失败");
    }

链接redis报错 ERROR org.springframework.boot. ; ERR invalid password;java.io.IOException:

缓存菜品数据

 @GetMapping("/list")//改造list
    public R<List<DishDto>> list(Dish dish){
        List<DishDto> dishDtoList =null;
        //动态构造key
        String key="dish_"+dish.getCategoryId()+"_"+dish.getStatus();//

        //1.先从redis中获取缓存数据,按照菜单分类缓存
        dishDtoList= (List<DishDto>) redisTemplate.opsForValue().get(key);

        if(dishDtoList != null) {
            //2.如果存在!=null,直接返回,不用查询数据库
            return R.success(dishDtoList);
        }
        //构造查询条件
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null ,Dish::getCategoryId,dish.getCategoryId());
        //添加条件,查询状态为1(起售状态)的菜品
        queryWrapper.eq(Dish::getStatus,1);

        //添加排序条件 排序顺序,创建时间倒序
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        List<Dish> list = dishService.list(queryWrapper);

        dishDtoList = list.stream().map((item) -> {
            DishDto dishDto = new DishDto();

            BeanUtils.copyProperties(item,dishDto);

            Long categoryId = item.getCategoryId();//分类id
            //根据id查询分类对象
            Category category = categoryService.getById(categoryId);

            if(category != null){
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }

            //当前菜品的id
            Long dishId = item.getId();
            LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
            //SQL:select * from dish_flavor where dish_id = ?
            List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);
            dishDto.setFlavors(dishFlavorList);
            return dishDto;
        }).collect(Collectors.toList());
        //3.不存在,需要查询数据库,将查询到的数据缓存到redis
        redisTemplate.opsForValue().set(key,dishDtoList,60, TimeUnit.HOURS);//60分钟

        return R.success(dishDtoList);
    }
@PostMapping
    public R<String> save(@RequestBody DishDto dishDto){
        log.info(dishDto.toString());

        dishService.saveWithFlavor(dishDto);
        //1.更新完 就清理所有缓存数据
        //Set keys = redisTemplate.keys("dish_*");//获得所有以‘dish_’开头的key
        //redisTemplate.delete(keys);

        //2.精确 清理缓存数据(只清理 被更新类别 的缓存数据)
        String key="dish_" + dishDto.getCategoryId()+"_1";
        redisTemplate.delete(key);
        return R.success("新增菜品成功");
    }

@PutMapping//改造update&save
    public R<String> update(@RequestBody DishDto dishDto){
        log.info(dishDto.toString());

        dishService.updateWithFlavor(dishDto);

        //1.更新完 就清理所有缓存数据
        //Set keys = redisTemplate.keys("dish_*");//获得所有以‘dish_’开头的key
        //redisTemplate.delete(keys);

        //2.精确 清理缓存数据(只清理 被更新类别 的缓存数据)
        String key="dish_" + dishDto.getCategoryId()+"_1";
        redisTemplate.delete(key);
        
        return R.success("修改菜品成功");
    }

Spring Cache框架

介绍 基于注解的缓存 (Cache译为缓存)

常用注解

#result: 代表方法返回值(condition关键字里没有result用unless代替); #root.method: 方法对象 ;

#root.args[0] / #p0 / #a0(a0我感觉也行) : 方法第一个参数

使用方式

缓存套餐数据

项目优化2—读写分离

Mysql主从复制

配置主库Master

先登录 mysql -uroot -p1234(你的密码)

GRANT REPLICATION SLAVE ON *.* to 'xiaoming'@'%' identified by 'Root@1234';(我的密码比他少两位)

从库Slave #192.168.138.132; root@1234

关闭防火墙链接mysql

 change master to master_host='192.168.138.100',master_user='xiaoming',master_password='Root@1234',master_log_file='mysql-bin.000001',master_log_pos=439;

后两个要跟这里的对应;

测试主从复制连接

主库怎么操作,从库也会复制操作;就说明链接成功

读写分离案例

背景

sharding-JDBC介绍

入门案例

项目实现读写分离

直接往主库里面导入,从库就会自动复制;

报错:

create connection SQLException, url: jdbc:mysql://192.168.138.100:3306/reggie?characterEncoding=utf-8, errorCode 0, state 08S01

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

create connection SQLException, url: jdbc:mysql://192.168.138.100:3306/reggie?characterEncoding=utf-8, errorCode 0, state 08S01

修改两个URL:

url: jdbc:mysql://192.168.138.101:3306/rw?characterEncoding=utf-8&useSSL=false

Nginx

Nginx概述

1.5安装wget

4.5 创建文件夹 :mkdir -p /usr/local/nginx ; 6:先编译然后 install; 安装tree命令查看目录结构

Nginx命令

查看版本

要先cd /usr/local/nginx/sbin

检查配置文件正确性

启动和停止

关闭防火墙: systemctl stop firewalld ; 如下页面,访问成功

重新加载配置文件

要写路径启动nginx -->不想写路径;

解决方案:把nginx的二进制文件路径配置到系统的环境变量 实现 nginx 即可启动的效果

vim /etc/profile
PATH=$JAVA_HOME/bin:$PATH   # 追加成下面的
PATH=/usr/local/nginx/sbin:$JAVA_HOME/bin:$PATH
source /etc/profile
nginx -s reload  # 不报错说明添加环境变量成功

Nginx配置文件结构

全局块、Events块、Http块

Nginx具体应用

部署静态资源

部署html成功

反向代理(用的最多)

区别:正向代理一般是在客户端设置代理服务器,

反向代理客户端不知道反向代理服务器的存在,客户端只需要访问服务器就会返回相应资源,用户不知道代理服务器存在。

负载均衡

项目优化3—前后端分离开发

前后端分离开发

介绍

开发流程

前端技术栈

Yapi (一种定义接口的Web服务)

YApi-教程

YApi-内网搭建

windows环境下部署YApi

我没有跟 原因是需要mangoDB

Swagger

介绍

使用方式

常用注解

项目部署

相关文章:

  • 2023-02-04 Elasticsearch 倒排索引的理解 Trie前缀树原理
  • 【DIY小记】VMWare设置主机连接到的Ubuntu虚拟机的网络端口
  • Spring Boot 集成Quartz
  • 【Java学习】JUC并发编程
  • 【入门AUTOSAR网络管理测试】CANoe测试T_STARTx_AppFrame时间
  • Apache Shiro身份验证绕过(CVE-2023-22602)
  • Cadence PCB仿真 使用 Allegro PCB SI 为电源网络分配电压并选择仿真的电源网络的方法图文教程
  • (考研湖科大教书匠计算机网络)第三章数据链路层-第六节媒体接入控制3:载波监听多址接入-碰撞避免(CSMA-CA)协议
  • ocs系统介绍
  • JVM运行时数据区
  • PMP考试答题技巧及注意事项
  • SSRF盲打 Collaborator everywhere
  • 49_逻辑漏洞
  • Spring Batch 作业启动方式
  • C++11 异常
  • R6220关于breed刷机,breed-2022-07-24 r1416
  • 【webpack】前端工程化与webpack
  • 基于linux5.15.5的IMX 参考手册 --- 16
  • node\npm问题
  • How to debug LLVM by VS2019 on Windows
  • 电加热油锅炉工作原理_电加热导油
  • 大型电蒸汽锅炉_工业电阻炉
  • 燃气蒸汽锅炉的分类_大连生物质蒸汽锅炉
  • 天津市维修锅炉_锅炉汽化处理方法
  • 蒸汽汽锅炉厂家_延安锅炉厂家
  • 山西热水锅炉厂家_酒店热水 锅炉
  • 蒸汽锅炉生产厂家_燃油蒸汽发生器
  • 燃煤锅炉烧热水_张家口 淘汰取缔燃煤锅炉
  • 生物质锅炉_炉
  • 锅炉天然气_天燃气热风炉