文章目录
软件开发的基本流程
二刷该项目主要是需要看接口文档去设计对应的代码,不跟着视频去敲
软件开发的基本流程
需求分析->设计->编码->测试->上线运维
IT公司对应职位,产品经理,UI设计师,架构师,开发工程师,测试工程师,运维工程师。
管理端 和用户端对应的功能
主要使用到的技术
基于springboot,使用Redis,swagger,JWT,webSocket,POI,mysql等技术。
用户层
本项目中在构建系统管理后台的前端页面,我们会用到H5、Vue.js、ElementUI、apache echarts(展示图表)等技术。而在构建移动端应用时,我们会使用到微信小程序。
网关层
使用Nginx作为http服务器,部署静态资源,访问性能较高。在Nginx中有两个比较重要的作用,反向代理和负载均衡,在项目部署的时候,需要实现Tomact的负载均衡,可以通过nginx来实现
应用层
springboot 快速构建spring项目,采用约定优于配置思想,简化开发
springMVC 实现拦截等功能的
springTask 实现定时任务的发送
SpringCache 实现数据缓存功能
JWT 实现用户登录的验证功能
阿里云OSS 对象存储服务,在项目中主要存储对应的文件,如图片等
Swagger:可以自动的帮助开发人员生成接口文档,并对接口进行测试
POI 封装了Excel的常用操作
WebScoket 一种通信网络的协议,是客户端和服务器之间的数据交换更加简单,用于项目的来单和催单功能实现
数据层
Mysql 关系型数据库,本项目的核心业务都会采用msql进行存储
Redis,基于key-value格式内存的数据库,访问速度快,经常用来做缓存
Mybatis 本项目持久层将会采用Mybatis开发
pagehelper:分页插件
spring data redis 简化Java代码操作Redis的API
工具
git 进行版本的控制工具,在团队协作中,使用改工具对项目进行代码管理
maven 项目构建工具
junit 单元测试工具,开发人员功能实现完毕后,需要进行测试
postman:接口测试工具,模拟用户发送各类的HTTP请求,获取对应的结果。
后端分模块开发
sky-common 存放一些公共类
sky-pojo 模块存放一些entity、DTO、VO
sky-server 存放Controller、service、mapper和启动类等
数据库设计
本项目的数据库设计很有技巧,到底如何设计对应的数据库呢?
1需要一个员工表
2 分类表
3 菜品表4菜品需要有对应的口味,菜品口味表
5 套餐表6套餐有对应的内容,需要一个套餐菜品表
7下单用户需要有用户表
8配送 需要地址表 9用户购物车表
10 下单需要存储订单表,还需要11订单明细表
导入准备好的前端和后端工程
在这段配置中,我们配置了Spring框架的一些属性。
首先,我们定义了profiles属性,指定了当前应用程序的活动配置文件为dev。此配置用于指定在不同环境中加载不同的配置。
接下来,我们定义了main属性。main属性用于配置Spring应用程序的主要设置。在这个例子中,我们设置了allow-circular-references属性为true。这意味着Spring容器将允许在bean之间存在循环引用。循环引用是指当一个bean依赖于另一个bean,而另一个bean又依赖于第一个bean时的情况。
通过设置allow-circular-references为true,Spring容器将尝试解决这种循环引用,并在必要时延迟注入依赖。这在某些情况下可能是必要的,但是需要小心使用,因为循环引用可能导致死循环或其他问题。
这是一个简单的Spring配置示例,用于设置活动的配置文件和允许循环引用。根据实际的应用程序需求,你可以在配置文件中进行更多的设置和自定义。
基础工程代码分析
完成员工功能
完成菜品功能
入门Redis+实现店铺营业
HttpClient+微信小程序开发
缓存+Spring Cache
实现地址功能+用户下单
实现订单推送状态
apache对应的工具使用
项目用到的技术进行分析
JWT
全称 JSON Web Token ,用于在通信双方以json数据格式安全的传输信息,用于数字签名的存在。
简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。
JWT由三部分组成:
第一部分 头,记录令牌的类型、签名算法等,例如:{“alg”:“HS256”,“type”:“JWT”}
第二部分 PayLoad 有效载荷,携带一些自定义的信息,默认信息等。列入:{" id":“1”,“username”:“Tom”}
第三部分 Signature(签名),防止Token被篡改,确保安全性。并加入指定秘钥,通过指定签名算法计算而来。
签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的
JWT是如何将原始的JSON格式数据,转变为字符串的呢?
其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号
需要注意的是Base64是编码方式,而不是加密方式。
JWT令牌最典型的应用场景就是登录认证:
- 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果登录成功之后,我们需要生成一个jwt令牌,将生成的 jwt令牌返回给前端。
- 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。
- 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接拒绝访问,如果带过来了,还要校验一下令牌是否是有效。如果有效,就直接放行进行请求的处理。
导入JTW依赖
io.jsonwebtoken
jjwt
0.9.1
JWT工具类
package com.sky.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
//JWT 工具类
public class JwtUtil {
/**
* 生成jwt
* 使用Hs256算法, 私匙使用固定秘钥
*
* @param secretKey jwt秘钥
* @param ttlMillis jwt过期时间(毫秒)
* @param claims 设置的信息
* @return
*/
//三个参数 一个是对应的密钥 然后就是对应的时间
//接着是对应的集合
public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
// 指定签名的时候使用的签名算法,也就是header那部分
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
// 生成JWT的时间
long expMillis = System.currentTimeMillis() + ttlMillis;
Date exp = new Date(expMillis);
// 设置jwt的body
JwtBuilder builder = Jwts.builder()
// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
.setClaims(claims)
// 设置签名使用的签名算法和签名使用的秘钥
.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
// 设置过期时间
.setExpiration(exp); //设置时间的格式是对应的Date
return builder.compact();
}
/**
* Token解密
*
* @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
* @param token 加密后的token
* @return
*/
public static Claims parseJWT(String secretKey, String token) {
// 得到DefaultJwtParser
Claims claims = Jwts.parser()
// 设置签名的秘钥
.setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
// 设置需要解析的jwt
.parseClaimsJws(token).getBody();
return claims;
}
}