首页 > 知识百科 > 正文

瑞吉外卖笔记原创

概述

功能架构图

数据库建库建表

表说明

< /p>

开发环境

Maven搭建

直接创建新工程
继承父工程的形式类似于这个,这里新建父工程
< br /> pom文件

服务器 端口 9001spring: 应用程序:< /span> 名称: ccTakeOut 数据源: 德鲁伊: 驱动程序类名称: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ruiji?serverTimezone=亚洲/上海&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true 用户名 span> root 密码 333 redis 主机 localhost #本地IP或者虚拟机IP 端口 6379 # 密码:root 数据库: 0 # 默认使用0号db 缓存 redis: 生存时间: 1800000 #设置缓存数据的过期时间,30分钟mybatis-plus span>: 配置: #在映射实体属性或者时,将数据库中表名和字段名中的下划线去掉,开启按照驼峰命名法映射 map-下划线转驼峰式 true  log-impl org.apache.ibatis.logging.stdout.StdOutImpl 全局配置< span class="46bd-3175-bb43-8798 token punctuation">: db-config: id-type: ASSIGN_ID

启动测试

创建测试类并启动

导入前端页面

导入

在默认页面和前台页面的情况下,直接把这个两者拖到资源目录下直接访问是访问不到的,因为被mvc框架拦截了
所以我们要编写一个映射类放行这些资源

创建配置映射类
< p>

访问成功

后台开发

数据库实体类映射

用mybatis plus来实现逆向工程
这里是老版本的逆向工程

  <依赖> <groupId>org.freemarker</groupId > <artifactId>freemarker</artifactId> <版本>2.3.30</版本> </依赖> <依赖> <groupId>com.baomidou</groupId> <artifactId>mybatis-加上-boot-启动器</artifactId> <版本>3.3.1</版本> </依赖> <!--mybatis-加上代码生成器依赖--> <依赖> <groupId>com.baomidou</groupId>  <artifactId>mybatis-加上- 生成器</artifactId> <版本>3.3 .2</版本> </依赖 >

具体怎么玩看这里
MP逆向工程教程

账户操作

登陆功能

前端页面


数据库

业务逻辑

这里两个字符串的比较没法用!=来实现,只能等于再取反来判断
直接上代码,这里不涉及服务层的操作

 /** * @param request 如果登陆成功把对象放入Session中,方便后续拿取 * @paramEmployee利用@RequestBody注解来解析引入外部的Json,同时用对象来封装 * @return */ @PostMapping(" /login") 公共 结果 登录(HttpServletRequest 请求 @RequestBody 员工 employee) { 字符串 密码=员工getPassword(); 字符串 用户名 = 员工getUsername(); log .信息("登陆"< span class="9b7b-fbf0-f29d-da39 token punctuation">); //MD5加密 MD5Util md5Util =  MD5Util() ; 密码=MD5Util< span class="cfcc-a0a8-6a5d-2375 token punctuation">。getMD5(密码); //通过账户查这个员工对象,这里不会走服务层了 < span class="60c2-c7c7-446c-46bd token class-name">LambdaQueryWrapper<员工> lambdaQueryWrapper =  LambdaQueryWrapper(< /span>); lambdaQueryWrappereq(员工: :getUsername用户名); 员工 empResult=employeeServicegetOne(lambdaQueryWrapper);//判断用户是否存在 if (!empResult.getUsername( )等于(用户名)){< !-- --> 返回 结果错误("账户不存在" ); //密码是否正确 }else if (!empResult.getPassword()等于(密码)) { 返回 结果错误(“账户密码错误”);//员工账户状态是否正常,1状态正常,0封禁 } else if (empResultgetStatus()! =1){  返回 结果错误("当前账户正在封禁"); //状态正常允许登陆 }else { log信息("登陆成功,账户存入session"); / /员工id存入session,请求.getSession( )setAttribute("使用",empResult .getId()); 返回 结果 success("登陆成功") ; } }

具体代码可以参考如下路径

com.cc.controller.EmployeeController

关于RequestBody何时使用

退出功能

点击退出

删除session对象

 /* * * @param request 删除request作用域中的session对象,就按登陆的request.getSession().setAttribute("employ",empResult.getId());删除employee就行 * @return */ <跨度class="af41-59d2-cfcc-a0a8 token 注解标点">@PostMapping("/logout") 公共 结果 登录< /span>(HttpServletRequest 请求) { //尝试删除 尝试 { 请求getSession ()removeAttribute(“使用”); }catch (异常 e){ //删除失败 < span class="af41-59d2-cfcc-a0a8 token keywords">返回 结果错误("登出失败")< /span>; } 返回 结果成功("登出成功"); }

完善登陆(添加过滤器)

这里的话用户直接url+资源名可以随便访问,所以要加个拦截器,没有登陆时,不给访问,自动跳转到登陆页面

过滤器配置类注解@WebFilter(filterName ="拦截器类名首字母小写",urlPartten=“要拦截的路径,比如/*”)
判断用户的登陆状态这块之前因为存入session里面有一个叫employee的对象,那么只需要看看这个session不在就知道他是否在登陆状态
注意,想存或者想获取的话,就都得用HttpServletRequest的对象来进行获取,其他request对象拿不到的

这里提一嘴
调用Spring核心包的字符串匹配类的对象,对路径进行匹配,并且比较返回结果
或许就为true

public static 最终 AntPathMatcher PATH_MATCHER =  AntPathMatcher(< /span>);


拦截拦截完成器跳转到登陆页面,在这里做处理

代码太多了,给个路径好啦,直接去Gitee看
请求的js代码路径:resource/backend /js/request.js
拦截器的路径:com.cc.filter.LoginCheckFilter

新增员工

新增员工功能,(前置对手机号和身份证号码长度做了一个校验)

请求URL:http://localhost:9001/employee (POST请求)
< br />
改造一下Employee实体类,通用id雪花自增算法来新增id

这里用service接口继承的MybatisPlus的功能

注入一下就可以使用了,插入方法

基本上都是自动CRUD,访问路径:com.cc.controller.EmployeeController

全局异常处理< /h3>

先看看这种代码的try catch
这种try catch来捕获异常固然好,但是,代码量一大起来,超级多的try catch就会很乱< /strong>

所以我们要加入全局异常处理,在Common包下,和结果同级,这里只是示例,并不完整


当报错信息出现重复条目​​时,就意味着增加了员工异常了
所以,我们对异常类的方法进行了一些小事情,让这个异常反馈变得更加人性化

这个时候再来客户端试试,就会提供人性化的报错,非常的快乐~

这又回到Controller,接下来就不需要再尝试catch这种形式了,不用管他,因为一旦出现错误就会被我们的AOP捕获。所以,不需要再用try catch来抓了

异常类位置:com.cc.common.GloableExceptionHandler

员工信息分页查询

接口分析

老生常谈分页查询了
需求

分页请求接口


查询员工及显示接口


逻辑流程

分页插件配置类

先弄个MP分页插件配置类
原因是和3.2.3版本的代码生成器冲突
分页插件爆红解决方案

直接注释掉

加入配置类

接口设计

接口注意事项


pageobject内部

里面包含了查询构造器的使用
具体的细节在这个包下:com.cc.controller.EmployeeController.page

 /** * 分页展示员工列表接口、查询某员工 * @param page 查询第几页 * @param pageSize 每页共几条数据 * @param name 查询名字=姓名的数据 * @return 返回页面页 */ @GetMapping("/page" ) 公共 结果<页面> 页面(int页面 < span class="af41-59d2-cfcc-a0a8 token 关键字">int pageSize,字符串 name){ //分页构造器,Page(第几页,查几条) Page pageInfo =  页面(< /span>page, pageSize); //查询构造器 LambdaQueryWrapper< 员工> lambdaQueryWrapper =< /span>  LambdaQueryWrapper(); //过滤条件.like(什么条件下启用模糊查询,模糊查询字段,被模糊插叙的名称) lambdaQueryWrapper.(!StringUtils isEmpty(名称), 员工 ::getName, name)< span class="60c2-c7c7-446c-46bd token punctuation">; //添加排序 lambdaQueryWrapper.orderByDesc(员工::getCreateTime); //查询分页、自动更新employeeService.页面(pageInfo, lambdaQueryWrapper)< /span>; //返回查询结果  返回 < span class="46bd-3175-bb43-8798 token class-name">结果成功(pageInfo); } 

启用、取消员工账号

无非就是修改状态,0禁用,1启用


这种根据登陆人物来进行判断的玩法,是前端
该页面的位置resource/backend/page/member/list.html

看关心来的对象消费者的,如果是admin,vue的v-if指令就会把编辑按钮显示出来
如果是隐藏普通用户就会把编辑按钮

修复一个小Bug

前端一直不显示编辑按钮,在localStorage里没有发现admin对象

这个值不应该是登陆成功,应该是Employee的对象Json
猜测是登陆的时候往请求里存对象没存好

改成对象存入就好了

这回都正常了

功能编写

复习一下
PutMapping是Resultful风格的请求方式
< br /> 当前状态是1,直接携带目标状态值(状态改禁用)进行更新

Id精度再损失,js强调的bug,直接处理长处理不了,要长转字符串返回去


利用对象转换器JacksonObjectMapper,将对象转Json
将Long类型的Id转换为String类型的数据

在MVC配置类中扩展一个消息转换器

测试功能正常,正常更新员工状态
消息扩展器配置位置:com.cc.common.JacksonObjectMapper
对象映射器位置:com.cc.config.WebMvcConfig
员工状态更新位置:com.cc.controller.EmployeeController

编辑员工信息


请求API,这个是先发请求,查到用户,然后填充到页面上
可以看出来,这种请求方式是ResultFul风格的请求方式
在控制器中使用@PathVariable(“/{参数名称}”)注解来进行接收


完美更新
更新方法位置:com.cc.controller.EmployeeController.getEmployee

公共字段自动填充

类似于部分公共字段,反复填充起来没有意义,简化填充的操作。
把这个功能拿出来,单独拎出来做自动填充处理


为实体类属性上面加入注解@ TableField(fill = 填充条件)
看一下源码。fill是填充条件,用枚举来进行处理的

加完注解和条件还不算完,还要加入配置类进行处理,对填充的数据做规定
在common包下创建一个自定义类,最关键的是要实现MetaObjectHandler接口下的insertFill和updateFill
确认填充时需要的字段。另外要加入@Component注解,将这个类迁移框架来管理,不然的话很容易找不到,setValue的值会根据注解加入的字段名称来确定是否需要更新
位置:com.cc.common.MyMetaObjectHandler

但是这里有问题,如果我想要更新管理员字段是非常困难的,因为我这里拿不到Request
这个时候就需要ThreadLocal来进行对象的获取,这个线程是贯穿整个运行的,可以通过他来获取

使用时

何为ThreadLocal
重点来了
这个图


我的思路就是在用户登陆的时候,把这个id存入,等到在填充字段的时候,从ThreadLocal里把这个资源再拿出来。我选择在Utils下创建

第一个Bug

具体包在utils里,有Bug,封装的类ThreadLocal获取不到数据,不太清楚为什么,暂时就这个写死了

//基于ThreadLocal封装工具类,用户保存并获取当前登录的用户id// ThreadLocal线程为作用域,保存每个线程中的数据副本public class BaseContext { 私有 静态 ThreadLocal< span 类 =“标记标点符号”><> threadLocal  =  ThreadLocal<>() ; //设置当前用户id public 静态 void setCurrentId( id){ threadLocal.设置(id); } 公共 静态  getCurrentId(){ 返回 threadLocal.获取(); }}

注意,ThreadLocal不是一个线程,只有同一个线程才能拿到,不是一个线程拿不到的

解决方案

更改setId的位置,存储的时候放在过滤器内部,就算是一个线程了,都能得到。不过我都试了一下过了,确实是一个线程,但是还是拿不
换个思路:因为我想拿Request对象里的Id嘛,所以,只要有Request的id就行,不一定足够执着一定用ThreadLocal来存,因此,我这里选择注入一下HttpServletRequest对象来解决这个问题。

菜品页面

菜品分类

涉及的表有分类表category

业务流程

新增菜品分类

请求方式为Post请求

控制器位置:com. cc.controller.CategoryController(保存)

菜品分类执行


还是那块结构

创建分页构造器 Page pageInfo = new Page (第几页,每页几条数据);如果需要条件过滤的加入条件过滤器LambaQueryWarpper注入的service对象(已经继承MP的BaseMapper接口)去调用Page对象
serviceobject.page(分页信息,条件过滤器)返回结果就可以了

分页查询位置:com.cc.controller.CategoryController.page

删除菜品分类



普通版本,没有考虑分类有关联的情况

完善一下,如果当前菜品分类下有菜品的话,不会删除许
所以在删除之前要先做判断才可以删除,不符合条件的,我们要发送异常进行提示
因为没有返回异常信息的类,我们在这里做一个自定义的专门返回异常信息的类CustomerException
这个类的位置仍然是common包下

因为我们之前创建了一个全局异常处理,也用上,因为要拦截异常统一处理
还是com.cc.common.GloableExceptionHandler
对发送异常进行处理,就可以对新增的异常提供目标的拦截和异常通知

删除菜品分类的controller接口在:com.cc.controller.CategoryController (delCategory)
由于业务特殊,且比较长,就分离出来把业务放在service包下
service接口位置:com.cc.service.impl.CategoryServiceImpl (removeCategory)

修改套餐信息< /h3>


非常简单的CRUD,直接调用MP更新一下就行
API位置

com.cc.控制器CategoryController (updateCategory)

文件上传下载(重点)

上传逻辑

第一次接触上传和下载的功能
文件上传逻辑(联系人) )

参数名有要求的
接收的文件类型一定是方法名(MultipartFile 外接上传的文件名称)


所以改为货运的接收名称也得文件

上传逻辑实现

具体的存储路径写在配置文件中里了

使用@Value注入到业务里就可以了

具体位置在com.cc.controller.CommonController (upLoadFile)

下载逻辑


图像回显功能
占用了输入流输出
位置: com.cc.controller.CommonController (fileDownload)

菜品管理页面

新增菜品

需求分析


涉及表为dish和dish_flavor

开发逻辑

新增实现

由于是多表的操作,MP直接干肯定不行,所以就把服务层抽离出来进行处理

还有,因为涉及几十表,这里还要加入事务进行控制,防止多表操作崩溃

 多表操作只能一个来,MP不能一次性操作多张表因为涉及到多表的问题,所以还要加入注解来处理事务@Transactional 开启事务@EnableTransactionManagement 在启动类加入,支持事务开启

Controller位置:com.cc.controller.DishController (addDish)
服务位置:com.cc.service.DishService
ServiceImpl位置:com.cc.service.impl.DishServiceImpl (addDishWithFlavor)

新增菜品之获取菜品种类


从接收一个type=1的标注,目的是在分类表中,菜品分类是1,套餐分类是2,把两个区分开,获取所有的菜品类型
< br /> 位置:com.cc.controller.CategoryController (listCategory)

菜品分页

顺手把菜品分页也做好了,不用写太多了,位置在:com.cc.controller.CategoryController(dishPage)
记录一个知识点,如果说头部没有类和前端要的数据对应,那么自己就可以封装一个类来对特殊硬件需要的数据进行封装

DTO对象

该类可以对一些实体类进行扩展,继承于某个父类,再添加一些内容
比喻Dish和DishDto
DishDto就继承于Dish类,并在此基础上进行了扩展

更新菜品信息

就是个更新

逻辑

注意,这里回显数据是使用DishDto,因为前端要显示口味等信息,这里如果使用Dish是无法完美显示的,所以用DishDto

回显填充查询

除此之外,这是个多表联查,用MP肯定不行,得自己写
控制器位置:com.cc.controller.DishController (updateDish)
服务位置:com.cc.service.DishService
ServiceImpl 位置:com.cc.service.impl.DishServiceImpl code>

更新实现

实际上就是两个表联动更新和删除操作,所以MP直接操作是不可以的,所以要在服务层自己再封装一个删除方法,给Controller层调用删除就行
对于Dish对象可以直接进行更新,因为DishDto是Dish的子类
因此可以调用DishService的更新方法命名DishDto对象,来实现Dish的更新
控制器位置:com.cc.controller.DishController (updateDish) 确实和上面那个一样,因为请求方式不一样
服务位置:com.cc.service.DishService < /code>
ServiceImpl位置:com.cc.service.impl.DishServiceImpl (updateDishWithFlavor)

其他功能

完成一些小功能的开发

停售功能

就是把数据库的状态值更新一下,两条路径,一个启售,一个停售

停售请求路径

如果状态不一样了,就会从停售变成启售,同时对应的请求路径也不一样


控制器位置: com.cc.controller.DishController (updateStatusStop)停止
控制器位置:com.cc.controller.DishController (updateStatusStart)启动

删除功能


菜品功能删除
逻辑完成删除,不是真删除< br />
位置:
控制器位置:com.cc.controller.DishController (deleteDish)停止

套餐页面

实际上就是一组菜品的集合

新增套餐概述

涉及到的数据库



导入SetmealDto
/>

新增套餐之菜品列表



控制器位置:com.cc.controller.DishController (listCategory)

新增套餐实现

和新增菜品差不多,这里也是多表的操作
控制器位置:com.cc .controller.SetmealController (saveSetmeal)
服务位置:com.cc.service.SetmealService
ServiceImpl 位置:com.cc.service.impl. SetmealServiceImpl(saveWithDish)

套餐分页

这里的套餐分页和以往不同的内容,设计到了多表

套餐分页Controller位置: com.cc.controller.SetmealController.pageList
套餐Mapper接口位置:com.cc.mapper.SetmealMapper
Mapper文件位置:resource.mapper.SetmealMapper

更新套餐

添加套餐和更新套餐几乎是完全一致的,字段巴拉巴拉的都一样

但是注意,修改套餐之后,需要先对菜品页面进行填充,这个页面都是需要填充填充要修改的菜品信息的。
先发请求,一看就是Restful风格请求

获取套餐控制器位置:com.cc.controller.SetmealController.getSetmal

更新销售状态



和前面一个业务逻辑很像,不想多赘述了,直接放接口位置
控制器位置:com.cc.controller.SetmealController (startSale/stopSale)< /p>

删除套餐

可以单独删除,也可以批量删除,接口是万金油,可以接,主要看热闹的数据是几个

< br /> 接口

== 多表删除,在Controller直接实现不太现实,所以要在Service把业务写好==
Controller位置:com.cc. controller.SetmealController (deleteSetmeal)
Service位置:com.cc.service.SetmealService
ServiceImpl位置:com.cc.service.impl.SetmealServiceImpl (removeWithDish)

前台开发(手机端)

账户登陆

短信发送



阿里云短信业务教程

代码实现

官方文档地址
导入Maven

<依赖> <groupId>com.aliyun</groupId > <artifactId>aliyun-java-sdk-核心</artifactId> <版本>4.5.16</版本> </依赖><依赖> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-dysmsapi</artifactId> <版本>1.1.0</版本> </依赖>


导入短信登陆的工具类,把ACCESSKeyID和Secret更换到位就行

验证码发送

数据模型用户表,手机验证码专用的表

开发流程

修改拦截器,放行操作


控制器位置:com.cc. controller.UserController (sendMsg)
发送完成还需要验证,验证就是另一个登录了

用户登陆


控制器位置:com.cc.controller.UserController (登录)< br />这里登陆还涉及到过滤器放行的功能,不要忘记了,把用户id存入会话,过滤器会进行验证
过滤器

控制器
< /p>

前台页面

导入用户地址簿


地址表

这里直接导入现成的AddressBookController,没有自己写

com.< /span>cc.控制器.AddressBookController

菜品展示

逻辑整理


修改DishController的列表方法,来满足前台请求的要求
控制器位置:com. cc.controller.DishController (listCategory)
套餐内菜品Controller:com.cc.controller.SetmealController (list)

购物车

把菜品加入购物车


逻辑整理

注意,这里需要设备去管总价的计算,就是单价*数量的这个操作,不是固定的内容。前端在展示的时候自己就计算了。
位置:com.cc .controller.ShoppingCartController (add)

下单


对应的两个表,一个是orders表,另一个是orders_detail表

orders表

orders_detail表

交互流程

业务比较复杂,在Service里写的com.cc. service.impl.OrdersServiceImpl

至此完成基础部分,开始对项目性能进行优化

小知识点总结

@RequestBody的使用< /h4>

只有外面的参数是Json才能用RequestBody接收,如果不是Json的情况(比如那种?key=value&key=value)是不能用的,会400错误
关于RequestBody何以使用时

服务器优化

基于Redis进行服务器优化

环境搭建

Redis进行配置

加入Pom文件

  <依赖><groupId>org.springframework.bootgroupId> <artifactId< /span>>spring-boot-starter-data-redisartifactId> 依赖>

加入Redis配置类

@Configurationpublic class RedisConfig 扩展 CachingConfigurerSupport { @Bean public RedisTemplate<对象, 对象> redisTemplate(RedisConnectionFactory connectionFactory) {< !-- --> 红色isTemplate<对象, 对象> redisTemplate =  RedisTemplate<>(); //默认的关键序列化器为:JdkSerializationRedisSerializer redisTemplatesetKeySerializer( StringRedisSerializer()); redisTemplate.setConnectionFactory(connectionFactory); 返回 redisTemplate; }}

yml中加入配置

短信验证码、登陆优化

给验证码加入有效时间的验证,设置好短信验证码的有效时间

如果登陆成功,就自动删除服务器中的验证码
优化位置:com.cc.controller.UserController sendMsg和login
注入RedisTemplete

针对验证码进行优化< br />
针对登录后进行优化
登录方法中


这里过滤器也要改,因为登陆的id数据由session变成了redis仓库,所以决定过滤器的相关部分进行改造

com.cc.filter.LoginCheckFilter

同样要先注入RedisTemplate

服务器前端菜品数据


服务器思路,要保证缓存数据库和DBMS内的数据保持同步,避免读读到数据(没更新的数据)

对DishController进行优化,加入了缓存
再次访问可以发现,如果已经缓存过了当前的菜品分类,就不会再查数据库了

更新菜品同时更新服务器

保证少出现脏数据,所以加入清理服务器,不及时清理的话,新数据保存上来,列表数据库无法同步更新。就会出现问题。
这里精确清理数据。大面积清存储也是比较费性能的
这种就是全清理

这种是精准清理

SpringCache

简介

< h4>SpringCache常用注解及功能

快速启动

启动类上要加入@EnableCaching注解,启用缓存框架< br />

@CachePut注解

服务器方法返回值,服务器一条或者多条数据

@CacheEvict注解
< p>删除服务器

@Cacheable注解

先看看Spring是否已经有服务器了当前数据,如果已经有服务器则直接返回。
如果没有服务器就直接存储到内存里

一些特殊情况,条件属性和除非属性

前面都是用SpringCache自带的存储容器,性能肯定比不了Redis
所以现在开始引入Redis作为SpringCache缓存的产品
切换为Redis作为缓存的产品

SpringCache-Redis


导入jar包

注入相对应的缓存产品Manager就可以了,这里以RedisManager为例

利用SpringCache-Redis来缓存套餐数据


启动类上要加入@EnableCaching注解,启用缓存框架

加入注解时的坑
这里实际上是从Return中拿到Setmeal中的属性,但是返回时的数据是Result封装的Setmeal数据,显然无法完成序列化,这里也需要对Result类进行序列化的改造

继承序列化类,从而可以进行序列化

=此时就完成了服务器的优化,此时如果服务器中当前缓存自动过期的时间在yml里面有详细配置

保存套餐方法缓存优化
一保存套餐,对应的服务器就得删除,因为数据更新了要重新获取
还有更新套餐,理由同上
删除方法要加

保存方法也要加< br />

数据库优化

MySQL读写分离

将单点数据库改建为整个数据库服务器
主写从读。

MySQL主从复制架构

主库设置

主从复制架构图
< br /> 以上就可以实现主库数据和从库数据保持同步

对主库进行配置
Linux改法

log-bin=mysql-bin #启动二进制server-id=100 #唯一id

windows改法

在mysql安装路径下

修改好了重启MySQL

< p>
windows版本的重启教程在这里
重启mysql

======================== =================================

授予 复制 SLAVE ON< span class="446c-46bd-3175-bb43 token 操作符">**'xiaoming'@'%'识别by 'Root@123456';

这里我把本地的MySQL作为主机,把阿里云作为从机
运行一下权限SQL

查看主机状态show master status;

从库设置

从库这里选择了阿里云
还是先修改配置文件,加入端口id


第二步还是从库重启(Linux中)

第三部分,设置连接到主机
运行SQL

运行一下
具体的可以去从机用show master status查看

将 master 更改为 master_host='ip',master_user='小明',master_password='Root@123456',master_log_file=< /span>'mysql-bin.eo0001',master_log_pos=主机的位置


这里我是有点服务器,一台docker安装的mysql(从机)
另一台是普通安装的mysql做主机,配置过程中遇到了很多问题,参考了下面的链接

参考教程

一定记着上面从机连接命令运行成功后要从机启动

slave start

最后运行start Slave是执行成功了

从机器状态查看一下

show Slave status

这样优质的搭建好了

测试




到这里搭建完成了

遇到的问题

这里遇到的问题,连不上

想本地当主机,外网当从机想不太行,我就又弄了台服务器做读写分离

搞到了从机之后,就开始配置,安装MySQL等等

有的时候会提示io冲突,这是因为之前的从机没有关闭,关闭一下就可以了
stop Slave一下就可以运行了

一个从机启动命令忘记了,改了一晚上
如果不运行从机启动就会变成这样

主写从读实战

概述


难么怎么去确定了的SQL应该分配到哪个库上,这个就要靠Sharding-jdbc框架来读写分离的分流处理

实战

步骤如下

导入Maven坐标

 <dependency > <groupId>org.apache .shardingsphere</groupId> <artifactId>分片-jdbc<跨度类=”令牌运算符">-spring-启动-starter< /artifactId> <版本>4.0.0 -RC1</版本> < span class="6a5d-2375-9b7b-fbf0 token operator"></依赖>

配置yml文件

spring: application: name: ccTakeOut shardingsphere: datasource: names: master从属#主库(增删改操作) master: 类型:com.alibaba.druid .pool.DruidDataSource 驱动-class-名称:com.mysql.cj.jdbc.驱动程序 URL:jdbc:mysql://121.89.200.204:3306/ruiji?characterEncoding= utf-8 用户名:root 密码:333 #来自数据源(读操作) 从属:< span class="60c2-c7c7-446c-46bd token keywords">类型:com.alibaba.druid..DruidDataSource 驱动程序-class-名称:commysqlcjjdbc .驱动程序地址:jdbc:mysql://121.36.51.170:3306/ruiji?characterEncoding=utf-8 用户名:root 密码:333 masterslave: #拆迁配置 负载-余额-算法- 类型:round_robin #轮询(如果有多个从库会轮询着读) #最终的数据源名称 name: dataSource #主库数据源名称 master-data-来源-name: master #来自库数据源名称列表,多个分隔分隔 从属-数据--名称:从属道具:sql显示true #开启SQL显示,默认false main:allow-bean-定义-覆盖:true  #允许bean允许数据源覆盖

解读一下yml配置

定义Bean覆盖很重要

测试

启动项目,可以看到,读写器操作分别到达了不同的主机上
读写器分离测试

Nginx配置

Nginx笔记< /p>

前玉米分离开发


开发流程

YApi

< p>

Swagger(常用)

主要作用就是帮助云端人员生成云端接口文档的

使用方式

导入坐标

 <!< span class="2375-9b7b-fbf0-f29d token comment">--knife4j接口管理--> <依赖> < span class="60c2-c7c7-446c-46bd token 操作符"><groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-启动-starter</artifactId> <版本>3.0.2</版本> </依赖>

导入配置类

具体配置位置< code>com.cc.config.WebMvcConfig

启动服务,访问路径+doc.html
进入之后就可以对已有的接口进行管理了
< /p>

Swagger常用注解

直接生成的注解内容并不很完善

Swagger常用注解

以实体类为例< br />
控制器上的注解

以上成果,最终完善好注解,文档会更好用,更详细。

部署项目

接口

作为接口一个工程,同样需要备份,完成备份为dist目录

把这个dist目录,扔进Nginx里HTML文件夹就可以了,一个静态资源

传上来不算,完还要配置一下
一个是静态资源,另一个是反向代理

静态资源配置

先配置静态资源

请求代理配置

重启Nginx,测试一下,访问。
随便一个请求就可以看到,带了出口

小米项目给的端口是9001
请求路径为:http://www.ccsmile.fun:9001/api/employee/login
我们这边是没有这个api的远端的
通过重写url,就可以把
http://www.ccsmile.fun:9001/api/employee/login
变成
http://www.ccsmile.fun:9001/employee/login的请求地址,这样就完成了请求代理转发操作

配置文件如下

server{ Listen 80;  server_name localhost;#静态资源配置 location /{ root html/dist; 索引 索引html; }#请求转发代理,重写URL+转发 location ^ ~ /api/{ 重写 < span class="2375-9b7b-fbf0-f29d token 运算符">^/api/(.*)$ < span class="3175-bb43-8798-af41 token 运算符">/$1 break; proxy_pass http://实验室服务ip:端口号; }#其他 error_page <跨度class="a0a8-6a5d-2375-9b7b 令牌编号">500 502 503 504  /50x.html; 位置 = / 50x.html{ root html; }}

最后保存文件,重启Nginx,就配置完成了
还是不知道啥不好用,还有待解决,实在不行就在云端上加入接收请求远程就好了

< h3> 起重机


上传脚本,自动拉取最新脚本
这样在开发端和Linux端就通过Gitee间接实现同步了

脚本内容

#!/bin/shecho =< /span>========运算符">==== =========== ===========echo 自动化配置启动脚本echo == =========== ========== ==========echo停止原来运行中的工程APP_NAME=reggie_take_outtpid=` ps -ef|grep $APP_NAME|grep -v grep|grep -v Kill|awk '{print $2}'`if [ ${tpid} ]; 然后 echo '停止进程。 ..' kill -15 $ tpidfisleep 2tpid=`< /span>ps -ef|grep $APP_NAME|grep -v grep|grep -v Kill|awk '{print $2}'`if [ ${tpid} ]; 然后 echo '终止进程!' kill< /span> -9 $tpidelse echo '停止成功!'fiecho 准备从 Git 仓库拉取最新代码cd /usr/本地/javaapp/ reggie_take_outecho 开始从Git仓库拉取最新代码git pullecho代码拉取完成echo 开始预算输出=`mvn clean package -Dmaven.test.skip=true`cd targetecho 启动项目nohup java -jar reggie_take_out-1.0-< /span>SNAPSHOT.jar &> reggie_take_out.log &echo 项目启动完成

执行脚本就OK了

记得yml文件中的部分内容,比如文件路径等等信息~
完成结撒花啦

瑞吉外卖笔记原创由知识百科栏目发布,感谢您对的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“瑞吉外卖笔记原创

Copyright © 2012-2023 普诚元亨工作室 版权所有

*本站部分网页素材及相关资源来源互联网,如有侵权请速告知,我们将会在24小时内删除*

Z-BlogPHP 1.7.3 琼ICP备2022020219号