瑞吉外卖2.0 Redis 项目优化 Spring Cache MySQL主从复制 sharding-JDBC Nginx YApi Swagger
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
通用操作,针对不同数据类型都可以操作
项目优化-缓存优化
环境搭建
配置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.
修改两个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
介绍
使用方式
反正就是maven依赖冲突 卡了三个小时还是解决不了 先往后走吧 主要是knife4j的Swagger框架pom.xml导不进去;
com.google.guava:guava:jar:27.0.1-android failed to transfer from https://repo.maven.apache.org/maven2 during a previous attempt. This failure was cached in the local repository and resolution is not reattempted until the update interval of central has elapsed or updates are forced. Original error: Could not transfer artifact com.google.guava:guava:jar:27.0.1-android from/to central (https://repo.maven.apache.org/maven2): transfer failed for https://repo.maven.apache.org/maven2/com/google/guava/guava/27.0.1-android/guava-27.0.1-android.jar
Try to run Maven import with -U flag (force update snapshots)
https://blog.csdn.net/yiguoxiaohai/article/details/125708088
几个月之后 ,当我又需要这个项目的时候又可以了 ,我想了一下 之前也总遇到导包不成功问题,有一次 我发现之前没设置Maven自动导包,后来设置上了;就导包成功了,可能是因为这个,又成了
因为两个数据库对的 所以我觉得就是我第二个虚拟机的mysql的版本不对 瑞吉的mysql是5.几
常用注解
项目部署
部署架构
部署环境说明
麻烦没搞
部署前端项目
部署后端项目
完结撒花!
本文来自博客园,作者:软工菜鸡,转载请注明原文链接:https://www.cnblogs.com/SElearner/p/17676681.html