本项目(苍穹外卖)是专门为餐饮企业(餐厅、饭店)定制的一款软件产品,包括 系统管理后台 和 小程序端应用 两部分。其中系统管理后台主要提供给餐饮企业内部员工使用,可以对餐厅的分类、菜品、套餐、订单、员工等进行管理维护,对餐厅的各类数据进行统计,同时也可进行来单语音播报功能。小程序端主要提供给消费者使用,可以在线浏览菜品、添加购物车、下单、支付、催单等。
1). 管理端
餐饮企业内部员工使用。 主要功能有:
模块 | 描述 |
---|---|
登录/退出 | 内部员工必须登录后,才可以访问系统管理后台 |
员工管理 | 管理员可以在系统后台对员工信息进行管理,包含查询、新增、编辑、禁用等功能 |
分类管理 | 主要对当前餐厅经营的 菜品分类 或 套餐分类 进行管理维护, 包含查询、新增、修改、删除等功能 |
菜品管理 | 主要维护各个分类下的菜品信息,包含查询、新增、修改、删除、启售、停售等功能 |
套餐管理 | 主要维护当前餐厅中的套餐信息,包含查询、新增、修改、删除、启售、停售等功能 |
订单管理 | 主要维护用户在移动端下的订单信息,包含查询、取消、派送、完成,以及订单报表下载等功能 |
数据统计 | 主要完成对餐厅的各类数据统计,如营业额、用户数量、订单等 |
2). 用户端
移动端应用主要提供给消费者使用。主要功能有:
模块 | 描述 |
---|---|
登录/退出 | 用户需要通过微信授权后登录使用小程序进行点餐 |
点餐-菜单 | 在点餐界面需要展示出菜品分类/套餐分类, 并根据当前选择的分类加载其中的菜品信息, 供用户查询选择 |
点餐-购物车 | 用户选中的菜品就会加入用户的购物车, 主要包含 查询购物车、加入购物车、删除购物车、清空购物车等功能 |
订单支付 | 用户选完菜品/套餐后, 可以对购物车菜品进行结算支付, 这时就需要进行订单的支付 |
个人信息 | 在个人中心页面中会展示当前用户的基本信息, 用户可以管理收货地址, 也可以查询历史订单数据 |
关于本项目的技术选型, 我们将会从 用户层、网关层、应用层、数据层 这几个方面进行介绍,主要用于展示项目中使用到的技术框架和中间件等。
1). 用户层
本项目中在构建系统管理后台的前端页面,我们会用到H5、Vue.js、ElementUI、apache echarts(展示图表)等技术。而在构建移动端应用时,我们会使用到微信小程序。
2). 网关层
Nginx是一个服务器,主要用来作为Http服务器,部署静态资源,访问性能高。在Nginx中还有两个比较重要的作用: 反向代理和负载均衡, 在进行项目部署时,要实现Tomcat的负载均衡,就可以通过Nginx来实现。
3). 应用层
SpringBoot: 快速构建Spring项目, 采用 "约定优于配置" 的思想, 简化Spring项目的配置开发。
SpringMVC:SpringMVC是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合,可以无缝集成。
Spring Task: 由Spring提供的定时任务框架。
httpclient: 主要实现了对http请求的发送。
Spring Cache: 由Spring提供的数据缓存框架
JWT: 用于对应用程序上的用户进行身份验证的标记。
阿里云OSS: 对象存储服务,在项目中主要存储文件,如图片等。
Swagger: 可以自动的帮助开发人员生成接口文档,并对接口进行测试。
POI: 封装了对Excel表格的常用操作。
WebSocket: 一种通信网络协议,使客户端和服务器之间的数据交换更加简单,用于项目的来单、催单功能实现。
4). 数据层
MySQL: 关系型数据库, 本项目的核心业务数据都会采用MySQL进行存储。
Redis: 基于key-value格式存储的内存数据库, 访问速度快, 经常使用它做缓存。
Mybatis: 本项目持久层将会使用Mybatis开发。
pagehelper: 分页插件。
spring data redis: 简化java代码操作Redis的API。
5). 工具
git: 版本控制工具, 在团队协作中, 使用该工具对项目中的代码进行管理。
maven: 项目构建工具。
junit:单元测试工具,开发人员功能实现完毕后,需要通过junit对功能进行单元测试。
postman: 接口测工具,模拟用户发起的各类HTTP请求,获取对应的响应结果。
开发环境搭建主要包含前端环境和后端环境两部分。作为服务端开发工程师, 我们课程学习的重心应该放在后端的业务代码上, 前端的页面我们只需要导入资料中的nginx, 前端页面的代码我们只需要能看懂即可
1). 前端工程基于 nginx
从资料中找到前端运行环境的nginx,移动到非中文目录下。
2). 启动nginx,访问测试
双击 nginx.exe 即可启动 nginx 服务,访问端口号为 80
http://localhost:80
后端工程基于 maven 进行项目构建,并且进行分模块开发。
1). 从当天资料中找到后端初始工程:
2). 用 IDEA 打开初始工程,了解项目的整体结构:
对工程的每个模块作用说明:
序号 | 名称 | 说明 |
---|---|---|
1 | sky-take-out | maven父工程,统一管理依赖版本,聚合其他子模块 |
2 | sky-common | 子模块,存放公共类,例如:工具类、常量类、异常类等 |
3 | sky-pojo | 子模块,存放实体类、VO、DTO等 |
4 | sky-server | 子模块,后端服务,存放配置文件、Controller、Service、Mapper等 |
对项目整体结构了解后,接下来我们详细分析上述的每个子模块:
模块中存放的是一些公共类,可以供其他模块使用
分析sky-common模块的每个包的作用:
名称 | 说明 |
---|---|
constant | 存放相关常量类 |
context | 存放上下文类 |
enumeration | 项目的枚举类存储 |
exception | 存放自定义异常类 |
json | 处理json转换的类 |
properties | 存放SpringBoot相关的配置属性类 |
result | 返回结果类的封装 |
utils | 常用工具类 |
模块中存放的是一些 entity、DTO、VO
分析sky-pojo模块的每个包的作用:
名称 | 说明 |
---|---|
Entity | 实体,通常和数据库中的表对应 |
DTO | 数据传输对象,通常用于程序中各层之间传递数据 |
VO | 视图对象,为前端展示数据提供的对象 |
POJO | 普通Java对象,只有属性和对应的getter和setter |
模块中存放的是 配置文件、配置类、拦截器、controller、service、mapper、启动类等
分析sky-server模块的每个包的作用:
名称 | 说明 |
---|---|
config | 存放配置类 |
controller | 存放controller类 |
interceptor | 存放拦截器类 |
mapper | 存放mapper接口 |
service | 存放service类 |
SkyApplication | 启动类 |
修改配置文件,把数据库的帐号密码改成自己的
使用Git进行项目代码的版本控制,具体操作:
访问Gitee - 基于 Git 的代码托管和研发协作平台,新建仓库
获取仓库地址
2.2.3 提交并推送到远程仓库
成功推送至远程仓库
序号 | 表名 | 中文名 |
---|---|---|
1 | employee | 员工表 |
2 | category | 分类表 |
3 | dish | 菜品表 |
4 | dish_flavor | 菜品口味表 |
5 | setmeal | 套餐表 |
6 | setmeal_dish | 套餐菜品关系表 |
7 | user | 用户表 |
8 | address_book | 地址表 |
9 | shopping_cart | 购物车表 |
10 | orders | 订单表 |
11 | order_detail | 订单明细表 |
先把服务端的引导类启动
后端的初始工程中已经实现了登录功能,直接进行前后端联调测试即可
实现思路:
1.Controller层
在sky-server模块中,com.sky.controller.admin.EmployeeController
/** * 登录 * * @param employeeLoginDTO * @return */ @PostMapping("/login") public Resultlogin(@RequestBody EmployeeLoginDTO employeeLoginDTO) { log.info("员工登录:{}", employeeLoginDTO); //调用service方法查询数据库 Employee employee = employeeService.login(employeeLoginDTO); //登录成功后,生成jwt令牌 Map claims = new HashMap<>(); claims.put(JwtClaimsConstant.EMP_ID, employee.getId()); String token = JwtUtil.createJWT( jwtProperties.getAdminSecretKey(), jwtProperties.getAdminTtl(), claims); EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder() .id(employee.getId()) .userName(employee.getUsername()) .name(employee.getName()) .token(token) .build(); return Result.success(employeeLoginVO); }
2.Service层
在sky-server模块中,com.sky.service.impl.EmployeeServiceImpl
/** * 员工登录 * * @param employeeLoginDTO * @return */ public Employee login(EmployeeLoginDTO employeeLoginDTO) { String username = employeeLoginDTO.getUsername(); String password = employeeLoginDTO.getPassword(); //1、根据用户名查询数据库中的数据 Employee employee = employeeMapper.getByUsername(username); //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定) if (employee == null) { //账号不存在 throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND); } //密码比对 if (!password.equals(employee.getPassword())) { //密码错误 throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR); } if (employee.getStatus() == StatusConstant.DISABLE) { //账号被锁定 throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED); } //3、返回实体对象 return employee; }
3.Mapper层
在sky-server模块中,com.sky.mapper.EmployeeMapper
package com.sky.mapper; import com.sky.entity.Employee; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface EmployeeMapper { /** * 根据用户名查询员工 * @param username * @return */ @Select("select * from employee where username = #{username}") Employee getByUsername(String username); }
注:可以通过断点调试跟踪后端程序的执行过程
对登录功能测试完毕后,接下来,我们思考一个问题:前端发送的请求,是如何请求到后端服务的?
前端请求地址:http://localhost/api/employee/login
后端接口地址:http://localhost:8080/admin/employee/login
前端请求地址 后端接口地址
很明显,两个地址不一致,那是如何请求到后端服务的呢?
nginx:Engine X,俄罗斯人开发的一个软件,早期作为邮件收发的服务器代理。随着后来的发展,也提供了其它的功能:
部署静态资源,供客户端访问
静态资源:资源文件的内容是不变的,比如:html,css,js,图片,音频,视频
把静态资源,使用web服务器部署,启动web服务器后,其它人就可以通过网络访问这个资源了。资源变成了web资源
作为反向代理服务器,实现负载均衡
作为邮件收发的服务器
nginx 反向代理,就是将前端发送的动态请求由 nginx 转发到后端服务器
那为什么不直接通过浏览器直接请求后台服务端,需要通过nginx反向代理呢?
提高访问速度
因为nginx本身可以进行缓存,如果访问的同一接口,并且做了数据缓存,nginx就直接可把数据返回,不需要真正地访问服务端,从而提高访问速度。
进行负载均衡
所谓负载均衡,就是把大量的请求按照我们指定的方式均衡的分配给集群中的每台服务器。
保证后端服务安全
因为一般后台服务地址不会暴露,所以使用浏览器不能直接访问,可以把nginx作为请求访问的入口,请求到达nginx后转发到具体的服务中,从而保证后端服务的安全。
nginx 反向代理的配置方式:
server{ listen 80; server_name localhost; location /api/{ proxy_pass http://localhost:8080/admin/; #反向代理 } }
proxy_pass:该指令是用来设置代理服务器的地址,可以是主机名称,IP地址加端口号等形式。
如上代码的含义是:监听80端口号, 然后当我们访问 http://localhost:80/api/../..这样的接口的时候,它会通过 location /api/ {} 这样的反向代理到 http://localhost:8080/admin/上来。
接下来,进到nginx-1.20.2\conf,打开nginx配置
# 反向代理,处理管理端发送的请求 location /api/ { proxy_pass http://localhost:8080/admin/; #proxy_pass http://webservers/admin/; }
当在访问http://localhost/api/employee/login,nginx接收到请求后转到http://localhost:8080/admin/,故最终的请求地址为http://localhost:8080/admin/employee/login,和后台服务的访问地址一致。
当如果服务以集群的方式进行部署时,那nginx在转发请求到服务器时就需要做相应的负载均衡。其实,负载均衡从本质上来说也是基于反向代理来实现的,最终都是转发请求。
nginx 负载均衡的配置方式:
upstream webservers{ server 192.168.100.128:8080; server 192.168.100.129:8080; } server{ listen 80; server_name localhost; location /api/{ proxy_pass http://webservers/admin;#负载均衡 } }
upstream:如果代理服务器是一组服务器的话,我们可以使用upstream指令配置后端服务器组。
如上代码的含义是:监听80端口号, 然后当我们访问 http://localhost:80/api/../..这样的接口的时候,它会通过 location /api/ {} 这样的反向代理到 http://webservers/admin,根据webservers名称找到一组服务器,根据设置的负载均衡策略(默认是轮询)转发到具体的服务器。
注:upstream后面的名称可自定义,但要上下保持一致。
nginx 负载均衡策略:
名称 | 说明 |
---|---|
轮询 | 默认方式 |
weight | 权重方式,默认为1,权重越高,被分配的客户端请求就越多 |
ip_hash | 依据ip分配方式,这样每个访客可以固定访问一个后端服务 |
least_conn | 依据最少连接方式,把请求优先分配给连接数少的后端服务 |
url_hash | 依据url分配方式,这样相同的url会被分配到同一个后端服务 |
fair | 依据响应时间方式,响应时间短的服务将会被优先分配 |
具体配置方式:
轮询:
upstream webservers{ server 192.168.100.128:8080; server 192.168.100.129:8080; }
weight:
upstream webservers{ server 192.168.100.128:8080 weight=90; server 192.168.100.129:8080 weight=10; }
ip_hash:
upstream webservers{ ip_hash; server 192.168.100.128:8080; server 192.168.100.129:8080; }
least_conn:
upstream webservers{ least_conn; server 192.168.100.128:8080; server 192.168.100.129:8080; }
url_hash:
upstream webservers{ hash &request_uri; server 192.168.100.128:8080; server 192.168.100.129:8080; }
fair:
upstream webservers{ server 192.168.100.128:8080; server 192.168.100.129:8080; fair; }
可以部署静态资源,变成web资源 静态资源:资源内容不会变。比如html,css,js,图片,音频,视频等等 部署方式:最简单的方式,把静态资源直接放到nginx里的html文件夹内 可以作为反向代理服务器,实现负载均衡 反向代理:是服务端的代理,客户端是无感知的 服务器集群,对象提供一个统一的访问入口。外界想访问时,只要记入口的地址即可 对服务器实现负载均衡:把客户端的请求,根据负载均衡的策略分发到目标服务器上 提高服务器的安全性:可以在反向代理里,做安全防护措施 提高对服务器的访问性能:可以在反向代理集成缓存,缓存热点数据。客户端访问时,nginx可以直接返回缓存的数据,不需要转发到服务器了 nginx的使用: upstream xxxx{ server 服务器的ip:端口; server 服务器的ip:端口; } server{ listen 80; server_name localhost; location 路径表达式{ proxy_paxx http://xxxx; } } nginx支持的负载均衡策略: 轮询:默认策略。nginx把客户端的所有请求,轮流分摊给每个目标服务器 适合于:多个目标服务器的性能相近的情况 加权轮询:nginx按照每个目标服务器的权重值,把客户端请求分发给目标服务器。权重:理解为每个服务器被访问到的机率 适合于:多个目标服务器的性能有差别的情况 最少连接:nginx把请求优先分发给 最空闲的目标服务器(处理的连接数最少的服务器) ip hash:同一个ip的客户端,始终访问到同一个目标服务器 适合于:目标服务器有集群,并且使用了session技术。就不需要再在服务器集群之间做session同步了 url hash:相同的url请求,分发到同一个服务器上 适合于:目标服务器做了数据缓存的情况 fair: 哪个目标服务器响应时间短,就优先分发给哪个服务器
问题:员工表中的密码是明文存储,安全性太低。
将密码加密后存储,提高安全性
使用MD5加密方式对明文密码加密
修改数据库中明文密码,改为MD5加密后的密文
打开employee表,修改密码
修改Java代码,前端提交的密码进行MD5加密后再跟数据库中密码比对
打开EmployeeServiceImpl.java,修改比对密码
/** * 员工登录 * * @param employeeLoginDTO * @return */ public Employee login(EmployeeLoginDTO employeeLoginDTO) { //1、根据用户名查询数据库中的数据 //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定) //....... //密码比对 // TODO 后期需要进行md5加密,然后再进行比对 password = DigestUtils.md5DigestAsHex(password.getBytes()); if (!password.equals(employee.getPassword())) { //密码错误 throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR); } //........ //3、返回实体对象 return employee; }
接下来,就要进入到项目的业务开发了,而我们的开发方式就是基本当前企业主流的前后端分离开发方式,那么这种方式就要求我们之前需要先将接口定义好,这样前后端人员才能并行开发,所以,这个章节就需要将接口文档导入到管理平台,为我们后面业务开发做好准备。
其实,在真实的企业开发中,接口设计过程其实是一个非常漫长的过程,可能需要多次开会讨论调整,甚至在开发的过程中才会发现某些接口定义还需要再调整,这种情况其实是非常常见的,但是由于项目时间原因,所以选择一次性导入所有的接口,在开发业务功能过程当中,也会带着大家一起来分析一下对应的接口是怎么确定下来的,为什么要这样定义,从而培养同学们的接口设计能力。
第一步:定义接口,确定接口的路径、请求方式、传入参数、返回参数。
第二步:前端开发人员和后端开发人员并行开发,同时,也可自测。
第三步:前后端人员进行连调测试。
第四步:提交给测试人员进行最终测试。
将课程资料中提供的项目接口导入YApi。访问地址:YApi Pro-高效、易用、功能强大的可视化接口管理平台,注册帐号并登录
1). 从资料中找到项目接口文件
2). 导入到YApi平台
在YApi平台创建出两个项目
五、Swagger
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(API Documentation & Design Tools for Teams | Swagger)。 它的主要作用是:
使得前后端分离开发更加方便,有利于团队协作。
接口的文档在线自动生成,降低后端开发人员编写接口文档的负担。
如果开发中接口和早期设计的接口不同,不需要花很多时间重新编写接口文档,Swagger会根据代码直接生成接口文档
功能测试
Spring已经将Swagger纳入自身的标准,建立了Spring-swagger项目,现在叫Springfox。通过在项目中引入Springfox ,即可非常简单快捷的使用Swagger。
knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍!
目前,一般都使用knife4j框架。
导入 knife4j 的maven坐标
在pom.xml中添加依赖
com.github.xiaoymin knife4j-spring-boot-starter
在配置类中加入 knife4j 相关配置
WebMvcConfiguration.java
/** * 通过knife4j生成接口文档 * @return */ @Bean public Docket docket() { ApiInfo apiInfo = new ApiInfoBuilder() .title("苍穹外卖项目接口文档") .version("2.0") .description("苍穹外卖项目接口文档") .build(); Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .select() .apis(RequestHandlerSelectors.basePackage("com.sky.controller")) .paths(PathSelectors.any()) .build(); return docket; }
设置静态资源映射,否则接口文档页面无法访问
WebMvcConfiguration.java
/** * 设置静态资源映射 * @param registry */ protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); }
访问测试
接口文档访问路径为 http://ip:port/doc.html ---> http://localhost:8080/doc.html
接口测试:测试登录功能
思考:通过 Swagger 就可以生成接口文档,那么我们就不需要 Yapi 了?
1、Yapi 是设计阶段使用的工具,管理和维护接口
2、Swagger 在开发阶段使用的框架,帮助后端开发人员做后端的接口测试
通过注解可以控制生成的接口文档,使接口文档拥有更好的可读性,常用注解如下:
注解 | 说明 |
---|---|
@Api | 用在类上,例如Controller,表示对类的说明 |
@ApiModel | 用在类上,例如entity、DTO、VO |
@ApiModelProperty | 用在属性上,描述属性信息 |
@ApiOperation | 用在方法上,例如Controller的方法,说明方法的用途、作用 |
接下来,使用上述注解,生成可读性更好的接口文档
在sky-pojo模块中
EmployeeLoginDTO.java
package com.sky.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; @Data @ApiModel(description = "员工登录时传递的数据模型") public class EmployeeLoginDTO implements Serializable { @ApiModelProperty("用户名") private String username; @ApiModelProperty("密码") private String password; }
EmployeeLoginVo.java
package com.sky.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @ApiModel(description = "员工登录返回的数据格式") public class EmployeeLoginVO implements Serializable { @ApiModelProperty("主键值") private Long id; @ApiModelProperty("用户名") private String userName; @ApiModelProperty("姓名") private String name; @ApiModelProperty("jwt令牌") private String token; }
在sky-server模块中
EmployeeController.java
package com.sky.controller.admin; import com.sky.constant.JwtClaimsConstant; import com.sky.dto.EmployeeLoginDTO; import com.sky.entity.Employee; import com.sky.properties.JwtProperties; import com.sky.result.Result; import com.sky.service.EmployeeService; import com.sky.utils.JwtUtil; import com.sky.vo.EmployeeLoginVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; /** * 员工管理 */ @RestController @RequestMapping("/admin/employee") @Slf4j @Api(tags = "员工相关接口") public class EmployeeController { @Autowired private EmployeeService employeeService; @Autowired private JwtProperties jwtProperties; /** * 登录 * * @param employeeLoginDTO * @return */ @PostMapping("/login") @ApiOperation(value = "员工登录") public Resultlogin(@RequestBody EmployeeLoginDTO employeeLoginDTO) { //.............. } /** * 退出 * * @return */ @PostMapping("/logout") @ApiOperation("员工退出") public Result logout() { return Result.success(); } }
启动服务:访问http://localhost:8080/doc.html
1. JavaBean实体类,也会根据不同的作用,有一些划分。苍穹外卖项目里划分为 entity:对应数据库表的实体类 DTO:Data Transfer Object,数据传输对象, 客户端提交参数到服务端,我们接收成DTO对象 VO:View Object,视图层对象, 用于给客户端返回的数据对象 2. 项目开发里要尽量避免魔法值 什么是魔法值:没头没尾突然就出来的一个值。比如: if(xxx==1){}, 这里的“1”就是魔法值 魔法值的危害:编写完代码之后,很难再知道这个值究竟代表什么意思,不利于项目的后期维护工作 如何避免魔法值:通常定义成常量,借助于常量名称,以及对常量的注释,对这个值进行说明 (或者定义成枚举+注释说明) 3. 项目里的异常:不同的业务问题,要抛出不同的异常。 苍穹项目里的异常,定义了一个BaseException,并且提供了各种类型的子异常,比如 PasswordErrorException表示密码错误 AccountLockedException表示帐号被锁定异常 我们在写代码时: 要根据不同的业务问题,抛出对应的异常 如果不确定用哪个异常类,最起码要抛出BaseException 4. 启动项目时建议以debug模式启动。如果出问题,可以随时打断点进行调试 5. 开发过程中,必须要熟练使用的工具有: 如果是浏览器发请求:熟练使用抓包工具F12-Network(网络),看请求和响应所有的数据 如果是自己做测试的:熟练使用Postman发请求,看请求和响应所有的数据 服务端的错误:熟练使用debug调试。可以把程序运行暂停、一步步执行,我们可以随时看到每一步代码执行的结果 6. 项目里不允许存储明文密码,必须要存储加密之后的密文 常用的算法:MD5,单向摘要算法,是单向不可逆,并且相同明文多次加密结果相同 实际开发中,密码的存储,通常是MD5加密 + 加盐 7. 项目通常都会集成Swagger或Knife4J,作用: 我们编写完成功能之后,可以直接在生成的接口页面上进行测试 还可以生成API接口文档,也可以导出离线文档,不必花太多时间用于编写接口文档上 常用的注解: Controller类上加 @Api(tags="Controller的描述") Controller里方法上加 @ApiOperation("方法的描述") Controller里方法参数,如果是实体类 实体类上加@ApiModel("对实体类的描述") 给实体类里属性加@ApiModelProperty("属性的描述") 要想使用生成的接口文档页面: 1. 先启动服务 2. 打开浏览器输入地址 http://localhost:端口/doc.html
1. nginx启动不了 nginx必须要放到没有中文、空格、特殊字符的路径里,否则会启动失败 操作系统帐号有权限问题,导致启动失败:在nginx里手动创建temp文件夹,再启动试一下。 端口80被占用了,导致nginx启动失败:修改nginx.conf文件,修改其它其它端口。 端口修改之后,浏览器访问地址就随之改变 网络按照TCP/IP体系: 应用层:在TCP基础上(找到电脑之后),再找某个软件,和这个软件通知。要根据端口,连接对应的软件,与之进行数据交互 传输层TCP/IP:用于在网络环境里找到某一台电脑,根据ip寻址 端口:就是在根据ip找到某台计算机之后,根据端口找到对应的软件,与软件进行数据传输交互 默认有65535个端口 端口是属于抢占性资源:哪个软件先占用了80端口,其它软件就用不了80端口了 如果启动软件时,发现它要用的端口已经被占用了,解决方案: 方案1:杀掉占用端口的进程,进程一结束就释放端口了,然后再启动自己的软件 Windows系统里,打开cmd,执行命令:netstat -ano | findstr ":端口"。查询结果里最后一列的数字就是进程的pid 再拿这个数字,去任务管理器里找到pid对应的进程,杀掉 方案2:修改软件的配置,使用其它端口。 nginx软件的配置文件,在conf/nginx.conf,其中的listen后边的数字就是要占用的端口 2. 依赖下载不成功,爆红 第1步:先clean,再重新编译 第2步:把pom.xml里爆红的依赖坐标删除掉,刷新项目;再重新添加,再刷新项目 第3步:找到本地仓库文件夹(C:\Users\用户名\.m2\repository),搜索所有的 *.lastUpdated 文件,把搜索到的结果全部删除掉 再执行2步 第4步:在idea里执行maven命令:mvn -U idea:idea 强制更新依赖