# test-parent
**Repository Path**: mofeibai/test-parent
## Basic Information
- **Project Name**: test-parent
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2021-07-26
- **Last Updated**: 2021-11-10
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 一. 项目总结(图书商城)
## 1. 项目背景
+ 图书商城,分为前台和后台
+ 前台负责用户的注册登录,浏览图书,购买图书,提交订单,结账和支付,以及订单的浏览
+ 后台负责管理员和供应商的登录,提交图书信息和供货数量和查看图书销售信息;管理员的登录,前台注册用户的管理,平台图书的管理,权限、角色、后台管理员用户的管理与维护
## 2. 运用技术
+ 整体框架使用Spring boot + SpringMVC + MyBatis,
+ 后台使用垂直架构,业务逻辑比较复杂,但用到的技术比较单一,后台页面主要使用EasyUI绘制,thymeleaf展示,前后端交互比较方便,但页面比较单一,其中根据ISBN获取图书信息使用了HttpClient调用远程api获取数据
+ 前台使用分布式架构,使用Zookeeper+Dubbo的分布式技术实现service业务与controller控制的分开管理;使用Redis实现单点登录,数据缓存,(redis锁,redis同步事务);使用DubboLCN+Redis同步事务(用于service的嵌套调用);使用Solr实现全文检索;使用阿里沙箱调用阿里的远程接口实现支付功能;使用websocket实现毁掉跳转(实现聊天室的自动刷新)
## 3. 功能模块
### 1. 后台的权限管理模块、后台的用户登录模块
+ t_manager_user (t_user_role) t_role (t_role_permission) t_permission
+ 用户与角色、角色与权限都为多对多的关系,在处理多对多关系中,有一个中间表,不映射实体类,只作为多表联查的连接,同事在实体类中,有一个list<>列表,用于映射查询结果
+ 权限管理即登录时通过用户名和密码,通过多表的连接,查询得到t_premission权限表中的权限,从而动态控制该登录用户所能拥有的权限。多表联查中中间表不用显示数据,仅仅作为连接
+ 权限管理为父子类,因为一个服权限下有若干个子权限,两者需要分开管理(父禁用,子禁用/父开启,子视情况而定–如果有多级父子权限,则需要使用递归)
+ 登录时,需要使用拦截器(xxxInterceptor implements HandlerInterceptor),拦截器的功能为限制未登录用户不能访问除登录外的其他页面;同时,根据session中存储的登录的用户信息,判断请求页面是否有权限进入,从而做出拦截或放行的响应
+ SpringMVC中对于拦截器的注册使用类InterceptorConfig implements WebMvcConfigurer,在类中重写addInterceptors(),在其中调用addInterecptor(new 拦截器).addUrlPatterns(“可以使用通配符”).excludeUrlPatterns()
+ **如果需要分页展示多对多表的数据,不能使用多表联查,这会导致查阅到的数据总条数偏多(1条数据A->n条数据)**,从而导致封装为实体类后每页得到的数据条数减少
+ 登录成功后,将用户数据保存到session中(更好的选择为保存到Redis中),并在退出登录时使用session.invalidate()方法删除整个session(更好的是调用session.removeattribute()方法–invalidate会清掉整个session,可能会导致跳转失败出错)
### 2. 后台的用户管理模块
+ t_user
+ 常规单表的CURD
> 对于模糊查询(搜索)业务,为了防止Sql注入的威胁,需要注意:
>
> + 对于特殊字符的转义(%_),对于这些字符进行转义,防止sql注入和查询错误的结果
> + 对于<>等特殊字符,需要替换为(\>\<),防止sql注入的危险
> + 在MyBatis中,使用#{参数名},由MyBatis替换为?并由JDBC进行预编译并替换为相应值,同样微课防止sql注入
> + 对于模糊挨训,使用bind关键字由myBatis进行标定
### 3. 后台的供应商提交审核,平台进行审核
+ t_book (t_book_supplier) t_supplier t_examine
+ 供应商提交中,用户供应商只需输入ISBN等少数信息,其他信息由HttpClient发送相应get或post请求到相应api返回json获取
+ 查询到的结果,先将数据保存到数据库,(甚至缓存到Redis),这样可以消去一直请求第三方服务的时间,提高效率
+ 对于书籍,书籍的价格和书籍的数量,总价等可以使用BigDecimal存储到数据库中(实体类中必须使用BigDecimal,)
> 只要涉及到钱的计算,都要使用BigDecimal进行存储和精确运算,而不是用Double或Float,以免产生不确定的结果
+ 书籍封面涉及文件上传 @RequestParam(“file”)MultipartFile file – 必须添加RequestParam注解,因为该属性为一个对象,Spring 不会自动添加
+ 文件上传不能上传到测试项目中,而是要一起打包到运行项目,即上传到target文件夹
> ResourceUtils.getURL("classpath:static").getPath()
>
> registry.addResourceHandler("/upload/**").addResourceLocations("file:"+cp); // 同事在注册类中重写 addResourceHandlers方法
+ 书籍与供应商同样为多对多的关系,某供应商某次提交,如果审核通过,则将数量累加到t_book_supplier中
### 4. 后台的书籍管理模块
+ 常规的多表CRUD
+ 根据供应商模糊查询时,只要含有其中一个供应商,就应该将此书籍信息显示出来,即在sql中要使用子查询(先查出指定supplierid的bookid,再指定bookid in (xx)获取)
### 5. 前台的登录模块(单点登录)
+ t_user
+ redis
+ 模拟session(cookie中的token)
+ 首次登录,将登录信息存储到redis中(设置一定过期时间),其key为cookie中而存储的token加上字符串拼接而成
+ 后面,只要有请求,通过拦截器拦截请求,获取请求中的cookie,用cookie中的token获取redis中的用户数据,如果正常获取,则表明已登录,正常通过,否则跳转到登录页面
+ 如果redis和cookie中其中一个无值,则返回登录页面查新登录(并且记录当前请求页面,登录结束后继续跳转到请求页面,实现记忆功能)
+ 对于redis中设置的过期时间,只要有请求,则将过期时间重新设置为初始值(防止突然过期)
### 6. 前台的全文检索模块
+ Solr (全文检索与分词)
+ Solr的Field配置
+ Solr也可以当做一个数据库,可以存储图书数据与分词数据
+ 设置高亮效果
### 7. 前台的查看书籍详情、提交购物车模块
+ t_book
+ 查看书籍详情,常规ajax请求并返回数据(通过jquery动态绘制页面)
+ 提交购物车时购物车可以通过redis进行存储,不用放到数据库中,效率更高
+ 可以使用购物用户id拼接字符串作为大key,用图书id作为小key ,用购买数量作为value
+ >注意前后端数据交互时使用json转换的格式问题,这是一个大坑
### 8. 前台的购物车结算,支付宝支付模块
+ t_order,t_order_book t_book
+ 从redis获取图书信息和购物车信息,进行展示
+ 结算金额要通过ajax,动态请求到后台计算,后台计算时用BigDecimal,而不能直接到前台进行计算(安全问题)
+ 数量的加与减也要通过ajax及时传到后台并返回新数据,更新到前台
+ 支付模块首先根据订单,金额等信息生成二维码,手机扫码发送请求到支付宝,支付宝回调本地服务器方法,就取得支付结果
## 4. 项目经验与教训
(1) 多表对多表的关系,且要求分页时,不能使用多表联查,而是根据一个表查询结果的主键,根据外键获取另外一个表的信息
(2)EasyUI中如果DataGrid中有a连接,则不能使用‘getSelected’获取所选行,这样会获取上一次点击的结果,而是通过‘getData’获取整行数据,然后再从中获取
(3)前后台通过json进行复杂数据传输时,通过fastjson进行转换,此时要注意转换的格式问题,传输复杂数据时可以用object类型进行传输,以免类型转换错误
(4)对于模糊查询,要对% _ < > 等特殊字符进行转义处理,防止sql 注入
(5)多使用ajax异步请求,请求返回前端的数据尽量格式规范,统一一种传输格式(status,msg,data)
(6)合理使用Rest风格进行后端请求,可以省去很多代码冗余(比如启用和禁用,可以在后端使用同一个请求,传入不同的状态)
(7)合理使用redis缓存,可以提高效率,减轻数据库的负担
(8)注意变量名的命名规范问题
(9)注意对于日志的输出和对异常的同意处理,在本项目中并没有实现
(10)对于类和方法的封装意识还有所欠缺,总是想到哪里写到哪里,缺乏面对对象,解耦合的思想,代码复用性很差
(11)对于基础知识集合、迭代器、箭头函数、反射等知识缺乏