一、重要知识点精讲
1.1 nginx反向代理
1. nginx反向代理好处:
1. 提高访问速度(可以进行缓存,如果访问相同资源可以直接响应数据)
2. 可以进行负载均衡(如果没有nginx前端只能固定地访问后端某一台服务器,加入nginx则可以将请求分发给后端不同的服务器)
3. 保证后端服务安全(前端不能直接请求到后端服务器,需要通过Nginx转发)
2. nginx反向代理的搭建:
location /api/ 的意思是如果请求能匹配上/api/这个字符串。
proxy_pass 该指令的作用是设定转发的目的地,其后跟的是转发的目的地址。
3. nginx负载均衡的配置:
在webservers里面定义一组服务器,用于承接访问负载:
4. nginx负载均衡的策略:
服务器不一定需要平均承接请求,可以通过更改参数赋以不同的权重:
1. 按F12可以打开浏览器的调试工具
2. 负载均衡:把大量的请求按照我们指定的指定的方式均衡的分配给集群中的每台服务器。
3. 备注写上TODO可以在IDEA下方的TODO列表看到待做的操作
二、项目开发介绍
2.1软件开发整体介绍
软件开发流程
1. 需求分析:需求规格说明书(word文档)、产品原型(静态网页展示功能图片)。
2. 设计:UI设计(用户界面,小到按钮,大到页面布局,人机交互)、数据库设计(表结构、字段、类型等)、接口设计。
3. 编码:项目代码、单元测试。
4. 测试:测试用例、测试报告。
5. 上线运维:软件环境安装、配置。
角色分工
软件环境
2.2 苍穹外卖项目介绍
项目介绍
为餐饮企业(餐厅、饭店)定制的一款软件产品。
功能架构:体现项目中的业务功能模块。
产品原型
产品原型:用于展示项目的业务功能(一般用静态的HTML页面+适当的说明文字进行展示),一般由产品经理进行设计。
技术选型
技术选型:展示项目中使用到的技术框架和中间件等。
三、环境搭建
3.1 开发环境搭建
前端环境搭建
先确保将nginx.exe放在无中文的目录下:
将监听的端口号更改为81,因为80端口时常被占用,如果用80端口可能会因为端口占用而无法打开!!
注意:这里配置的是nginx的监听端口,nginx在81号端口上监听网页端,最后是将数据传入8080端口的服务器端。
后端环境搭建
1. 熟悉项目框架
common存放的是公共类。constant常量类。context项目上下文。enumeration枚举类。exception异常类。json处理json转换的类。properties是Springboot中的一些配置属性类,会把配置文件中的配置项封装成对象。result后端的返回结果。utils工具类。
pojo存放的是一些entity、DTO、VO
server子模块存放的是配置文件、配置类、拦截器、controller、service、mapper、启动类等。
2. 使用Git进行版本控制
.gitignore中都是要忽略的文件:
VCS-Create Git Repository创建远程仓库,选中根目录即可,若右上角出现标志说明成功:
勾选所有文件,编写记录文字,点击Commit:
在gitee上创建远程仓库:
点击赋值按钮,在IDEA中点击向上的按钮:
点击下面的链接,然后将刚刚复制的粘贴进来点击OK:
然后直接点击Push即可,然后刷新一下gitee页面,会发现同步成功:
3. 搭建数据库
一共11张表如下:
将已经提供的建表语句粘贴到查询处,点击运行,左边建立成功11张表:
4. 前后端联调
要先将连接数据库的密码改为自己的密码:
在右端Maven处选中compile进行编译,若显示BUILD SUCCESS则说明编译通过:
在sky-server目录下的SkyApplication类中启动项目:
输入localhost:81可以打开登录页面:
调试方法
打上断点,点击小虫:
光标放在字段上还会显示接收到的数据:
若想程序在所希望的地方停止,可以添加断点,然后点击左下角的按钮,意思是放行:
执行之后会在其中标明注入的数据:
按f12进入到开发者工具,点击登录,可以看到请求的路径:
但出现问题,前端请求的地址和后端接口的地址不一致是如何请求成功的呢?
nginx反向代理
但为什么需要NGINX进行转发呢?有什么好处呢?详细见1.1
3.2 完善登录功能
思路:将密码加密后进行存储,提高安全性。加密方式采用MD5。存储入数据库的数据将会是加密后的数据。并且加密的过程是不可逆的,无法通过加密结果算出明文。
e10adc3949ba59abbe56e057f20f883e记得要Ctrl+S保存更改结果:
只需调用Spring提供的DigestUtils类中的md5DigestAsHex方法传入密码即可将密码变成密文,提供给后面比对。
password = DigestUtils.md5DigestAsHex(password.getBytes());
四、接口文档和Swagger
4.1 导入接口文档
在开发之前需要先将接口定义好,然后前后端人员并行开发。
前后端分离开发流程
操作步骤
4.2 Swagger
Swagger介绍
使用Swagger只需要按照规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面。Swagger可以帮助后端生成接口文档、进行在线接口测试。
Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。
Swagger使用方式
导入下面坐标:
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-starter</artifactId><version>3.0.2</version>
</dependency>
相关配置:
@Beanpublic 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;}
设置静态资源映射:
protected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
Swagger常用注解
@Api注解使用样例:
@ApiModel注解使用样例:
@ApiModelProperty注解使用样例:
@ApiOperation注解使用样例:
注解影响如下图:
五、员工功能模块制作
5.1 新增员工
1.需求分析和设计
一般是对产品原型(静态HTML页面)分析,因为比较直观。思考录入项有没有什么限制。
密码采用默认密码,登录后可以进行修改。
接口定义如下:
数据库设计如下:
2.代码开发
当前端提交的数据和实体类中对应的属性差别较大是,建议使用DTO来封装。
1. 首先在EmployeeController中编写如下代码,EmployeeDTO是网页端读入的字段数据,在这里传入employeeService中:
@PostMapping//post方式请求@ApiOperation("新增员工")//请求路径在类的头部已加过public Result save(@RequestBody EmployeeDTO employeeDTO){ //声明参数接收前端数据,json数据要在前面加@RequestBodylog.info("新增员工:{}",employeeDTO);//方便调试employeeService.save(employeeDTO);return Result.success();//表示插入成功}
2. 然后再EmployeeService中编写如下代码:
//新增员工void save(EmployeeDTO employeeDTO);
3. 再在EmployeeServiceImpl中完成save()方法的编写,主要是添加除了employeeDTO以外字段的内容:
@Overridepublic void save(EmployeeDTO employeeDTO) {Employee employee = new Employee(); //创建Employee实体//对象属性拷贝,可以一次性拷贝过来BeanUtils.copyProperties(employeeDTO,employee); //employeeDTO是源,employee是目标,从源拷贝到目标//调用copuProperties方法的前提:属性名必须先是一致的//设置账号的状态,默认正常状态,1表示正常,0表示锁定employee.setStatus(StatusConstant.ENABLE);//设置密码,默认密码employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));//存入数据库要对密码进行md5加密//PasswordConstant.DEFAULT_PASSWORD中存储密码”123456“employee.setCreateTime(LocalDateTime.now());//设置当前记录的创建时间和修改时间employee.setUpdateTime(LocalDateTime.now());//设置当前记录创建人id和修改人id//TODO 后期需要改为当前登录用户的idemployee.setCreateUser(10L);employee.setUpdateUser(10L);employeeMapper.insert(employee);//调用持久层插入数据}
4. 最后呢调用了一个EmployeeMapper执行了SQL语句,来将数据插入数据库:
@Insert("insert into employee(name,username,password,phone,sex,id_number,create_time,update_time,create_user,update_user,status)" //数据库字段+ "values" +"(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})") //实体类字段void insert(Employee employee); //单表新增操作,没必要写入xml,通过注解完成
下面是开启驼峰命名:
3.功能测试
下面进行测试出现401,是因为有拦截器进行了拦截,原因是缺少token令牌:
所以我们先在员工登录页面获取一个令牌:
全局参数设置-输入参数名称+参数值,然后关闭页面:
然后带着参数值发送:
成功在数据库中添加记录:
下面是前后端联调成功:
4.代码完善
问题1:录入的用户名已存在,抛出异常后没有处理
用全局的异常处理器sky-server-handler-GlobalExceptionHandler,在方法里添加如下代码:
@ExceptionHandlerpublic Result exceptionHandler(SQLIntegrityConstraintViolationException ex) {String message = ex.getMessage();if(message.contains("Duplicate entry")){String[] split = message.split(" ");String username = split[2];String msg = username + MessageConstant.ALREADY_EXISTS;return Result.error(msg);}else{return Result.error(MessageConstant.UNKNOWN_ERROR);}
}
问题2:新增员工时,创建人id和修改人id设置为了固定值
程序中将id写死为10:
JWT认证机制:用户发起请求发送用户名和密码,后端进行校验,如果验证通过就生成JWT Token,将Token返回给客户端,客户端会保存Token,在后续请求的请求头中都会携带JWT Token,请求会被拦截器拦截到,会检查Token,如果通过就会展示数据,如果没有通过就会返回错误信息。
问题是:在解析处登录员工id后如何传递给Service的save方法?
答:通过ThreadLocal,它是Thread的局部变量,为每个线程提供单独一份的存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,在线程外则不能访问。
先在拦截器JwtTokenAdminInterceptor里将ID存到存储空间里,因为每次请求线程不变,所以存储空间的值不会被更改,因此可以在EmployeeServiceImpl类中取到该值,进而输出,很妙!
5.2 员工分页查询
1. 需求分析和设计
分页展示,每页展示10条数据,可以输入员工姓名进行查询。
2. 代码开发
3. 功能测试
4. 代码完善