1.分析项目存在的问题y3-1
前端和后端分离开发是指专门的前端开发人员负责项目开发过程中前端代码的开发,后端代码由后端开发人员负责,分工明确,各司其职,提高开发效率,并行开发前端和后端代码,加快项目开发进度。目前,越来越多的公司采用前端和后端分离开发模式,已成为当前项目开发的主流开发模式。
前端和后端分离开发后,工程结构也会发生变化,即前端和后端代码不再混合在同一maven工程中,而是分为前端工程和后端工程。
●VisualStudioCode
●hbuilder
技术框架●nodejs
●VUE
●ElementUI
●mock
●webpack
3.yapiy3-33.1介绍y3-3-3YAPI是一个高效、易用、功能强大的API管理平台,旨在为开发、产品和测试人员提供更优雅的接口管理服务。它可以帮助开发人员轻松地创建、发布和维护API。YAPI还为用户提供了良好的互动体验。开发人员只需使用平台提供的接口数据来编写
接口管理可以通过进入工具和简单的点击操作来实现。
YApi使接口开发更加简单高效,使接口管理更加可读、可维护,使团队合作更加合理。
源码地址:https://github.com/YMFE/yapi
要使用YAPi,需要自己部署。
具体操作的部署不演示,这不是重点,可以理解
使用Swager,您只需要根据其规范定义接口和接口相关信息,然后通过Swager衍生出的一系列项目和工具生成各种格式的接口文档和在线接口调试页面。
官网:https://swagger.io/
knife4j是JavaMVC框架集成Swager生成Api文档的增强解决方案。
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.2</version></dependency>
4.2使用方法y3-4操作步骤:
1、导入knife4j的maven坐标
2、导入knife4j相关配置类别
3、设置静态资源,否则接口文档页面无法访问
4、在LogincheckFilter中设置不需要处理的请求路径
在master创建新的分支v1.2
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.2</version></dependency>
4.2.导入knife4j相关配置类别我们已经有了这个类别,只需要添加相关的注释
@Bean public Docket createRestApi() { // 文档类型 return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.itheima.reggie.controller")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title(瑞吉外卖) .version("1.0") .description(瑞吉外卖接口文件) .build(); }
4.2.3设置静态资源,否则接口文档页面无法访问y3-4@Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { log.info(”静态资源映射开始..."); //设置静态资源,否则,接口文档页面将无法访问 y3-4 registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/"); registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/"); }
4.2.4在LogincheckFilter中设置不需要处理的请求路径y3-4浏览器输入http://localhost:8080/doc.html
成功
导出文档
以setmeal和R和setmealcontrler为例
Setmealpackage com.itheima.reggie.entity;import com.baomidou.mybatisplus.annotation.FieldFill;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableField;import com.baomidou.mybatisplus.annotation.TableId;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import java.io.Serializable;import java.math.BigDecimal;import java.time.LocalDateTime;/** * 套餐管理 3-8 */@Data@ApiModel(“套餐”) ///加入实体书名注释,目的是让我们生成更清晰的界面文档 3-5publiclicy class Setmeal implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(主键) private Long id; //分类id @ApiModelProperty(“分类id”) private Long categoryId; ///套餐名称 @ApiModelProperty(“套餐名”) private String name; ///套餐价格 @ApiModelProperty(“套餐价”) private BigDecimal price; //状态 0:停用 1:启用 @ApiModelProperty(“状态”) private Integer status; //编码 @ApiModelProperty(“套餐号”) private String code; //描述信息 @ApiModelProperty(描述信息) private String description; //图片 @ApiModelProperty(图片) private String image; @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; @TableField(fill = FieldFill.INSERT) private Long createUser; @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser; //是否删除 private Integer isDeleted;}
Rpackage com.itheima.reggie.common;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import java.io.Serializable;import java.util.HashMap;import java.util.Map;//通用返回结果 ,服务器的响应数据最终将被包装成这个对象 8@Data@ApiModel(“返回结果”)public class R<T> implements Serializable { //继承Serializable接口 y1-14 @ApiModelProperty(“编码”) private Integer code; /编码:1成功,0和其他数字是失败的 @ApiModelProperty(“错误信息”) private String msg; //错误信息 @ApiModelProperty(数据”) private T data; //数据 @ApiModelProperty(动态数据) private Map map = new HashMap(); ///动态数据 public static <T> R<T> success(T object) { R<T> r = new R<T>(); r.data = object; r.code = 1; return r; } public static <T> R<T> error(String msg) { R r = new R(); r.msg = msg; r.code = 0; return r; } public R<T> add(String key, Object value) { this.map.put(key, value); return this; }}
SetmealControllerpackage com.itheima.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.itheima.reggie.common.R;import com.itheima.reggie.dto.SetmealDto;import com.itheima.reggie.entity.Category;import com.itheima.reggie.entity.Setmeal;import com.itheima.reggie.service.CategoryService;import com.itheima.reggie.service.SetmealDishService;import com.itheima.reggie.service.SetmealService;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import io.swagger.annotations.ApiOperation;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.Cacheable;import org.springframework.web.bind.annotation.*;import java.util.List;import java.util.stream.Collectors;///套餐管理控制层 5-3@RestController@RequestMapping("/setmeal@Slf4j@Api(tags = “套餐相关接口”) //y3-5publiclicicicic class SetmealController { @Autowired private SetmealService setmealService; @Autowired private SetmealDishService setmealDishService; ///方便我们在查询套餐分页时使用 5-9 @Autowired private CategoryService categoryService; /*///新包装 5-5 5-6 @PostMapping public R<String> save(@RequestBody SetmealDto setmealDto){ log.info(包装信息 {}",setmealDto); setmealService.saveWithDish(setmealDto); return R.success(“新套餐成功”); }*/ ///新包装 优化 y1-14 @CacheEvict(value = "setmealCache",allEntries = true) @PostMapping @ApiOperation(value = “新套餐接口”) public R<String> save(@RequestBody SetmealDto setmealDto){ log.info(包装信息 {}",setmealDto); setmealService.saveWithDish(setmealDto); return R.success(“新套餐成功”); } ///套餐信息分页查询 5-9 @GetMapping("/page") @ApiOperation(value = “套餐分页查询接口” //y3-5 @ApiImplicitParams({ @ApiImplicitParam(name = "page",value = "页码",required = true), @ApiImplicitParam(name = "pageSize",value = “每页记录数”,required = true), @ApiImplicitParam(name = "name",value = “套餐名”,required = false) }) public R<Page> page(int page,int pageSize,String name){ //分页结构器 Page<Setmeal> pageInfo = new Page<>(); Page<SetmealDto> setmealDtoPage = new Page<>(); //添加查询条件 LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>(); //添加查询条件 like模糊查询根据名称进行 queryWrapper.like(name!=null,Setmeal::getName,name); //添加排序条件,根据更新时间的顺序排序 queryWrapper.orderByDesc(Setmeal::getUpdateTime); //执行分页查询 ///这个句子将包装我们查询到的数据 所有包装在Page的对象pageInfo setmealService.page(pageInfo,queryWrapper); ///这个时候这种情况和菜品分页查询的原因是一样的。我们这里的套餐分类名称无法显示,因为 // 我们传输id,前端需要name 解决方案与菜肴的分页查询相同 //复制pageinfo给setmealDtopage,但不复制records,因为pageinfo对应的泛型是setmeal //我们需要的是SetmealDto ///这个副本只是副本page对象的普通属性,不包括records属性集合 BeanUtils.copyProperties(pageInfo,setmealDtoPage,"records"); List<Setmeal> records = pageInfo.getRecords(); List<SetmealDto> list = records.stream().map((item)->{ ///这个setmealdto是我们新new出来的,里面的属性是空的,我们需要赋值 SetmealDto setmealDto = new SetmealDto(); ///将Setmeal的普通属性复制到SetmealDto BeanUtils.copyProperties(item,setmealDto); ///获得套餐分类idid Long categoryId = item.getCategoryId(); ////根据套餐分类id查询分类对象 Category category = categoryService.getById(categoryId); if(category!=null){ ////获得套餐分类的名称 String categoryName = category.getName(); ///将分类名赋值给setmealDto对象 setmealDto.setCategoryName(categoryName); } return setmealDto; }).collect(Collectors.toList());///收集这些setmealDto对象并集合 ///经过以上操作,我们得到了它 套餐分类名称 的 一般来说,setmealDto是setmel 的集合 setmealDtoPage.setRecords(list);///给setmealdtopagerecords赋值 return R.success(setmealDtoPage); } /** * 删除套餐 * @param ids * @return */ /* @DeleteMapping public R<String> delete(@RequestParam List<Long> ids){ log.info("ids:{}",ids); setmealService.removeWithDish(ids); return R.success(“成功删除套餐数据”); }*/ /** * 删除套餐 优化 y1-14 * @param ids * @return */ //allEntries = true 表示删除setmealCache下的所有缓存数据 @CacheEvict(value = "setmealCache",allEntries = true) @DeleteMapping @ApiOperation(value = “套餐删除接口”) public R<String> delete(@RequestParam List<Long> ids){ log.info("ids:{}",ids); setmealService.removeWithDish(ids); return R.success(“成功删除套餐数据”); } /** * 根据条件查询套餐数据 6-6 * @param setmeal * @return */ /*@GetMapping("/list") public R<List<Setmeal>> list(Setmeal setmeal){ LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(setmeal.getCategoryId() != null,Setmeal::getCategoryId,setmeal.getCategoryId()); queryWrapper.eq(setmeal.getStatus() != null,Setmeal::getStatus,setmeal.getStatus()); queryWrapper.orderByDesc(Setmeal::getUpdateTime); List<Setmeal> list = setmealService.list(queryWrapper); return R.success(list); }*/ /** * 根据条件查询套餐数据优化 y1-14 * @param setmeal * @return */ @Cacheable(value = "setmealCache",key = "#setmeal.categoryId+'_'+#setmeal.status") @GetMapping("/list") @ApiOperation(value = “套餐条件查询接口”) public R<List<Setmeal>> list(Setmeal setmeal){ LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(setmeal.getCategoryId() != null,Setmeal::getCategoryId,setmeal.getCategoryId()); queryWrapper.eq(setmeal.getStatus() != null,Setmeal::getStatus,setmeal.getStatus()); queryWrapper.orderByDesc(Setmeal::getUpdateTime); List<Setmeal> list = setmealService.list(queryWrapper); return R.success(list); }}
在浏览器中输入测试http://localhost:8080/doc.html
成功,有了中文解释,可读性更强
服务器:
●192.168.163.100(服务器A)
Nginx:部署前端项目,配置反向代理
Mysql:复制结构中的主库
●192.168.163.102(服务器B)
jdk:运行ava项目
git:版本控制工具
maven:工程建设工具
jar:基于内置Tomcat的springBoot项目打造jar包
Mysql:从库中主要从复制结构
●192.168.163.100(服务器A)
Redis:缓存中间件
5.3部署前端资源y3-7上传前端打包的dist目录E:\java\lingsanziliao
配置nginx
刷新
复制一个标签,启动nginx
访问浏览器输入http:/192.168.163.
访问成功
点击登录查看浏览器发送请求y3-7
新建一哥javappp
将项目克隆到javapp中
脚本reggiestartart.sh
#!/bin/shecho =================================echo 自动部署脚本启动echo =================================echo 停止原运行中的工程APP_NAME=reggie_take_out11tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'`if [ ${tpid} ]; then echo 'Stop Process...' kill -15 $tpidfisleep 2tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'`if [ ${tpid} ]; then echo 'Kill Process!' kill -9 $tpidelse echo 'Stop Success!'fiecho 准备从Git仓库提取最新代码cd /usr/local/javaapp/reggie_take_out11echohohout 最新代码gitt开始从Git仓库提取 pullecho 代码拉取完成echo 开始打包mvn clean package -Dmaven.test.skip=true > output.logcd /usr/local/javaapp/reggie_take_out11/targetecho nohup启动项目 java -jar reggie_take_out11-1.0-SNAPSHOT.jar &> reggie_take_out11.log &echo 项目启动完成
脚本在E:\java\lingsanziliao
上传脚本regiestartart.sh到javaapp
修改权限
执行脚本
查看java运行过程,说明没有问题
访问http:/192.168.163.
成功!!!
但另一个问题是,我们的图片资源无法显示
查看以下操作日志
很明显,在寻找图片资源时处理问题,因为这条路径是windows路径,在java文件中也可以看到
因此,我们需要修改指定的新路径
修改图片资源路径
在img目录中创建图片
上传图片
再次执行脚本
访问http:/192.168.163.
成功
到目前为止,项目已经完成
