宠物联盟这个项目是一个o2o模式项目。它是以宠物为中心,提供宠物领养,寻主的基本功能,还提供了宠物洗澡、修理毛发等宠物服务还有宠物粮食、玩具等宠物物品的购买,还提供了宠物相关知识学习等功能一个综合性平台。它主要有组织机构,系统,用户,服务,宠物,订单,支付等模块。它是使用前后端分离开发模式,前端使用的是vue技术栈,后台使用的是springboot+ssm+docker。
后台:Springboot、Spring、MyBatis、FastDFS、Redis、中国网建短信接口、百度地图、微信三方登录、支付宝支付、md5加密技术、邮件技术、Quartz
前端:Vue技术栈( nodejs、npm、webpack、vuecli、elmentui、easymock)
部署:Linux、Docker
3.1.domain创建
在开发中每个类都需要写getter与setter方法,以及覆写toString。Lombok插件可以让开发中省略这部分重复的工作。
3.2.controller创建采用Restful风格
Restful是一种面向资源的架构风格,可以简单理解为:使用URL定位资源,用HTTP动词(GET,POST,DELETE,PUT,PATCH(批量操作))描述操作。资源使用名词表示:资源是通过url描述,也就是在url不要出现动词
传输数据方式json:数据传输方式之一 对象:{} 数组:[{},{}]
Restful优点:
1)拥有http的优点
本身就是http,无状态,不用关心两次访问上下文.
2) 透明性,暴露资源存在
看到命令就知道要做什么了
3) 充分利用 HTTP 协议本身语义。
原来只用get,post,现在连delete和put
3.3.接口测试
1) postmain 测试 就是httm协议接口测试工具
2) 接口规范swagger
接口描述注解:
https://blog.csdn.net/xupeng874395012/article/details/84896063?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.channel_param
导入jar包:
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
//添加配置类
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//对外暴露服务的包,以controller的方式暴露,所以就是controller的包.
.apis(RequestHandlerSelectors.basePackage("org.zhou"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("系统中心api")
.description("系统中心服务接口文档说明")
.contact(new Contact("", "", ""))
.version("1.0")
.build();
}
}
4.1.ElementUI构建
npm i element-ui -S //elementui安装
//main.js引入
import Vue from 'vue';
import ElementUI from 'element-ui'; //引入核心js组件
import 'element-ui/lib/theme-chalk/index.css';//引入依赖的样式
Vue.use(ElementUI)
4.2.mockjs数据模拟
Mock.js (官网http://mockjs.com/)是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试。提供了以下模拟功能:根据数据模板生成模拟数据、模拟 Ajax 请求,生成并返回模拟数据、基于 HTML 模板生成模拟数据
特点:
前后端分离;让前端攻城师独立于后端进行开发;增加单元测试的真实性;通过随机数据,模拟各种场景;开发无侵入;不需要修改既有代码;就可以拦截 Ajax 请求;返回模拟的响应数据;用法简单;符合直觉的接口;数据类型丰富;支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等;方便扩展;支持支持扩展更多数据类型,支持自定义函数和正则。
安装
npm install mockjs
4.3. Ajax请求优化-axios
Axios和其他的ajax库都很类似,他是基于promise的http库,可以用在浏览器和node.js中理解 就是ajax请求 --在vue里面axios
安装
npm install axios --save
5.1.跨域问题
因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击
方案1
前端跨域(vue-cli)-proxytable
proxyTable: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': '' //类似于nginx反向代理所有以api开头的访问
}
},
},
main.js
//配置axios的全局基本路径
axios.defaults.baseURL='/api'
方案2
后端跨域-corsFilter(vuecli+div(css))
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://127.0.0.1:8081");
config.addAllowedOrigin("http://localhost:8081");
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
// 4)允许的头信息
config.addAllowedHeader("*");
//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new
UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
方案3
Nginx跨域
6.1.Git交互流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hoZ92Cur-1601047084119)(C:\Users\75851\AppData\Roaming\Typora\typora-user-images\image-20200925170031824.png)]
6.2.冲突解决
更新(pull)–手动解决冲突-告诉已解决(resove)–本地提交–push
Redis 是一个高性能的开源的、C语言写的Nosql(非关系型数据库),数据保存在内存中。
Redis 是以key-value形式存储,和传统的关系型数据库不一样。不一定遵循传统数据库的一些基本要求,比如说,不遵循sql标准,事务,表结构等等,redis严格上不是一种数据库,应该是一种数据结构化存储方法的集合。
数据结构:数组,list,set,map等
7.1.优点
1) 数据存储:存放在内存,还支持持久化.-存取速度快,并发能力强,数据安全高
2) 支持value类型更多
3) 支持多个语言客户端
4) 还支持集群(支持高并发,海量数据)
7.2.项目使用
Springboot Spring data redis:简化spirngdata对redis的配置
导包
org.springframework.boot
spring-boot-starter-data-redis
# redis 属性信息
## redis数据库索引(默认为0)
spring.redis.database=0
## redis服务器地址
spring.redis.host=localhost
## redis服务器连接端口
spring.redis.port=6379
## redis服务器连接密码(默认为空)
spring.redis.password=123456
## 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
## 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
## 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1ms
## 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
7.3.持久化
Redis 提供了两种不同级别的持久化方式:RDB和AOF,可以通过修改redis.conf来进行配置.
RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照,默认开启该模式.
如何关闭 rdb 模式:
save ""
# save 900 1 //至少在900秒的时间段内至少有一次改变存储同步一次
# save xxx
# save 60 10000
AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集,默认关闭该模式。
如何开启aof模式:
appendonly yes //yes 开启,no 关闭
# appendfsync always //每次有新命令时就执行一次fsync
#这里我们启用 everysec
appendfsync everysec //每秒 fsync 一次
# appendfsync no //从不fsync(交给操作系统来处理,可能很久才执行一次fsync)
其它的参数请大家看redis.conf配置文件详解
7.4.淘汰策略
volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从所有数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从所有数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据
redis 确定驱逐某个键值对后,会删除这个数据并,并将这个数据变更消息发布到本地(AOF 持久化)和从机(主从连接)。
8.1.店铺入驻相关
店铺审核,禁用,绑定商家支付宝信息,绑定商家微信信息,绑定商家银行卡信息
8.2.Fasdfs 店铺logo上传
FastDFS 是用 c 语言编写的一款开源的分布式文件系统。FastDFS 为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
FastDFS 架构包括 Tracker server 和 Storage server。客户端请求 Tracker server 进行文件上传、下载,通过 Tracker server 调度最终由 Storage server 完成文件上传和下载。
Tracker server 作用是负载均衡和调度,通过 Tracker server 在文件上传时可以根据一些策略找到 Storage server 提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器。
Storage server 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上,Storageserver 没有实现自己的文件系统而是利用操作系统 的文件系统来管理文件。可以将storage称为存储服务器。
后台接口
@RestController
@RequestMapping("/dfs")
public class FastDfsController {
@PostMapping
public AjaxResult upload(@RequestPart(required = true,value = "file") MultipartFile file){
try {
System.out.println(file.getOriginalFilename() + ":" + file.getSize());
String originalFilename = file.getOriginalFilename();
// xxx.jpg
String extName = originalFilename.substring(originalFilename.lastIndexOf(".")+1);
System.out.println(extName);
String filePath = FastDfsUtil.upload(file.getBytes(), extName);
return AjaxResult.me().setResultObj(filePath); //把上传后的路径返回回去
} catch (IOException e) {
e.printStackTrace();
return AjaxResult.me().setSuccess(false).setMessage("上传失败!"+e.getMessage());
}
}
/**
* 参数:完整路径 /goup1/xxxxx/yyyy
* 返回值:成功与否,还要返回地址
*
*/
@DeleteMapping
public AjaxResult del(@RequestParam(required = true,value = "path") String path){
String pathTmp = path.substring(1); // goup1/xxxxx/yyyy
String groupName = pathTmp.substring(0, pathTmp.indexOf("/")); //goup1
String remotePath = pathTmp.substring(pathTmp.indexOf("/")+1);// /xxxxx/yyyy
System.out.println(groupName);
System.out.println(remotePath);
FastDfsUtil.delete(groupName, remotePath);
return AjaxResult.me();
}
}
8.3.邮件发送
配置类
# 设置邮箱主机(服务商)
spring.mail.host=smtp.qq.com
# 设置用户名
[email protected]
# 设置密码,该处的密码是QQ邮箱开启SMTP的授权码而非QQ密码
spring.mail.password=qzbxiwjfrweecacf
# 必须进行授权认证,它的目的就是阻止他人任意乱发邮件
spring.mail.properties.mail.smtp.auth=true
#SMTP加密方式:连接到一个TLS保护连接
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
邮件demo
@Test
public void test2() throws Exception{
//创建复杂邮件对象
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
//发送复杂邮件的工具类
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"utf-8");
helper.setFrom("[email protected]");
helper.setSubject("新型冠状病毒防护指南");
http://img30.360buyimg.com/popWaterMark/jfs/t1/67988/7/14094/232759/5db64acfE6ab2b09e/38b5cb3dc38b4b1f.jpg"
helper.setText("新型冠状病毒防护守则
"+
"",true);
//添加附件
helper.addAttachment("罗宾.jpg",new File("C:\\Users\\hm\\Desktop\\work\\aa.jpg"));
helper.addAttachment("压缩文件", new File("C:\\Users\\hm\\Desktop\\20191010\\2020-02-05-智能商贸-DAY4\\resources\\resources.zip"));
//收件人
helper.setTo("[email protected]");
javaMailSender.send(mimeMessage);
}
9.1.登录表设计
后台一个方法完成两种登录
以后只要在eployee或user操作时涉及到登录信息都要同步操作logininfo。比如添加员工也要在logininfo添加一条记录,注册用户也要在logininfo中添加。同理删除或修改也要同步。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jph53JW0-1601047084122)(C:\Users\75851\AppData\Roaming\Typora\typora-user-images\image-20200925213218014.png)]
9.2.流程设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BWPyWfEf-1601047084126)(C:\Users\75851\AppData\Roaming\Typora\typora-user-images\image-20200925213355987.png)]
9.3.短信注册流程
短信接口采用中国网建
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EjGbuGUz-1601047084130)(C:\Users\75851\AppData\Roaming\Typora\typora-user-images\image-20200925213458654.png)]
9.4.MD5加密技术
1、 不可逆加密技术,只能加密不能解密。 只能做比对,一般用来加密用户登录密码。
我们要做的是把传入进行加密和数据库查询出来密文进行比对判断密码是否正确。
2 、盐值:同一种加密算法,由于不同的盐值,加密出来就不一样。
1)整个系统使用同一个盐值,多个用户共用-定义一个常量
2)每个用户都有自己盐值,就算是相同的密码,两个用用户加密出来也不一样。
9.5.前台登录
1)后台登录接口
2)前台登录实现并且保存uUser和uToken到localStorage
3)前台通过axios的前置拦截器携带token到后台
4)后台做token的登录拦截器,如果没有回报错给前台
5)前台通过axios后置拦截器对后台登录拦截错误进行跳转到登录页面
6)前台也要做拦截-有的地址是不需要访问后台
9.6.三方登录–微信登录
三方登录简介
我们的网站,可以作为三方,在主流平台(微信,qq,支付宝等等)登录,然后自己平台就不需要登录了。基于用户在主流平台上已有的账号和密码来快速完成己方应用的登录或者注册的功能。而这里的主流平台,一般是已经拥有大量用户的平台,国外的比如Facebook,Twitter等,国内的比如微博、微信、QQ等。 第三方登录的目的是使用用户在其他平台上频繁使用的账号,来快速登内录己方产品,也可以实现不注容册就能登录,好处就是登录比较快捷,不用注册。
三方登录依赖
OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAUTH的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAUTH是安全的。oAuth是Open Authorization的简写,目前的版本是2.0版。
OAuth 2.0的运行流程图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LNGX6FGH-1601047084132)(C:\Users\75851\AppData\Roaming\Typora\typora-user-images\image-20200925222718706.png)]
客户端必须得到用户的授权,才能获得令牌,OAuth2.0定义了四种授权方式:
授权码模式(authorization code)
简化模式(implicit)
密码模式(resource owner password credentials)
客户端模式(client credentials)
这里,我们主要介绍一下授权码模式:
授权码模式是功能最完整,流程最严密的授权模式。它的特点是通过客户端的后台服务器,与“服务提供商”的认证服务器进行互动
微信登录流程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-khdiITZH-1601047084134)(C:\Users\75851\AppData\Roaming\Typora\typora-user-images\image-20200925222850233.png)]
10.1.富文本编辑器
//下载安装
npm install quill --save
npm install vue-quill-editor
10.2.商品上架下架
业务说明:所谓上下架就是和超市里面业务差不多。 也就是平台添加服务用户时不能里面查看到的,需要上架以后才能查看。反之如果下架了以后,用户就不能查看到了 对于我们做系统而言就要对服务进行上下架处理。并且这种处理应该是批量操作。
10.3.寻主信息
寻主消息被平台分发给最近店铺,店铺管理员查看消息:
1)待处理寻主消息
①联系用户接回宠物
②宠物进行入库
③如果是要钱的宠物-创建寻主订单并支付
2)已处理寻主消息-记录
3)店铺管理员只能看到自己店铺的消息
4)平台管理员可以看到所有的消息
10.3.百度地图
百度申请ak
页面嵌入百度地图
后台工具类解析地址的经纬度
public static Point getPoint(String address){
String Application_ID="326Kn5caKgsLQaiYUpGkUf1w3UpIFIh1";//配置上自己的百度地图应用的AK
// String Application_ID="bZdIzawfzYoZ2cukPLM0CgOb2PK8rgtH";//配置上自己的百度地图应用的AK
try{
String sCurrentLine; String sTotalString;sCurrentLine ="";
sTotalString = "";
InputStream l_urlStream;
// URL l_url = new java.net.URL("http://api.map.baidu.com/geocoder/v2/?address="+address.replaceAll(" ","")+"&output=json&ak="+Application_ID+"&callback=showLocation");
URL l_url = new java.net.URL("http://api.map.baidu.com/geocoding/v3/?address="+address+"&output=json&ak="+Application_ID+"&callback=showLocation");
HttpURLConnection l_connection = (java.net.HttpURLConnection) l_url.openConnection();
l_connection.connect();
l_urlStream = l_connection.getInputStream();
java.io.BufferedReader l_reader = new java.io.BufferedReader(new InputStreamReader(l_urlStream));
String str=l_reader.readLine();
System.out.println(str);
//用经度分割返回的网页代码
String s=","+"\""+"lat"+"\""+":";
String strs[]=str.split(s,2);
String s1="\""+"lng"+"\""+":";
String a[]=strs[0].split(s1, 2);
s1="}"+","+"\"";
String a1[]=strs[1].split(s1,2);
Point point=new Point();
point.setLng(Double.valueOf(a[1]));
point.setLat(Double.valueOf(a1[0]));
return point;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
System.out.println(getPoint("地址"));
}
流程设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pi4ND8IR-1601047084135)(C:\Users\75851\AppData\Roaming\Typora\typora-user-images\image-20200925230833932.png)]
收购订单
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yTLeolkJ-1601047084136)(C:\Users\75851\AppData\Roaming\Typora\typora-user-images\image-20200925230924930.png)]
支付方式选择
现金支付:用户立马就能获取到钱,员工定时报账。
余额支付:付款余额,用户可以提现。 平台相当于给了用户钱,店家用给平台钱。
银行转账:银行转账,店家财务依次给用户转账。
int point=new Point();
point.setLng(Double.valueOf(a[1]));
point.setLat(Double.valueOf(a1[0]));
return point;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
System.out.println(getPoint("地址"));
}
#### 十一、订单模块
流程设计
[外链图片转存中...(img-Pi4ND8IR-1601047084135)]
收购订单
[外链图片转存中...(img-yTLeolkJ-1601047084136)]
支付方式选择
现金支付:用户立马就能获取到钱,员工定时报账。
余额支付:付款余额,用户可以提现。 平台相当于给了用户钱,店家用给平台钱。
银行转账:银行转账,店家财务依次给用户转账。