# 校园生活一站式平台 **Repository Path**: zjl0409/xyshpt ## Basic Information - **Project Name**: 校园生活一站式平台 - **Description**: 123456749879 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-03-21 - **Last Updated**: 2024-11-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 校园生活一站式平台 ## 1.项目主要功能介绍: 本项目主要针对在校大学生,主要功能包括但不限于二手物品交易,在线发布“皇榜”寻求有偿帮助。用户登入后可以根据自己的需要,寻找合适酬金的皇榜并揭取皇榜。也可以检索直系学姐学长的二手物品,可以线上支付,线下交易,核验物品后交易能够更加透明的拿到心仪的物品,不必忍受等待之苦以及欺骗之苦。 ## 2.项目技术介绍 后端: 主要框架:Spring Cloud , Spring Boot , Spring , Spring MVC , Spring Security , JWT ,Mybatis , Mybatis plus , Nacos注册服务 , Redis缓存服务 , RebbitMQ , Elasticsearch ,docker部署 前端: Vue 2.0/3.0 Android 数据库:mysql 8.0 ## 3.微服务拆分 采用微服务架构,项目目录: nacos——nacos注册中心目录 路径:http://1.117.41.158:8848/nacos/index.html#/login feign-api——feign的远程调用 (李伟华在做) user-service——用户基本权限模块 (周金磊在做) gateway——网关权限控制模块 (李伟华在做) order-service——订单交易模块 (陈锦涛在做) serch-hb-service——检索皇榜模块 search-es-service——检索二手模块 (陈锦涛在写) elasticsearch作为数据库 servicecenter——核心交易模块(李伟华) ## 3.项目架构图 ![输入图片说明](img/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84.png) ## 4.数据库设计 ### 4.1 数据库基本信息 数据库名称、数据库表格名称采用**下划线命名法**:如:tb_user_sign 数据库表字段采用**小驼峰命名法**:userId 数据库字符集:utf8 数据库排序规则:utf8_bin ### 4.2 数据库表及字段 #### 4.2.1 user_db 作用:用户基本权限模块所用到的数据库 **tb_user_basis**:(用户基本信息) | 字段名 | 类型 | 是否主键 | 注释 | | :---------------: | :-----: | :------: | :------------------------: | | userId | int | 是 | 用户编号 | | userUsername | varchar | 否 | 用户名称 | | userHeadimageId | int | 否 | 用户头像图片id,存在默认值 | | userBirthDatetime | varchar | 否 | 个人出生时间 | | userPayPassword | varchar | 否 | 用户支付密码 | | userAsset | float | 否 | 用户余额 | **tb_user_sign**:(用户登录) | 字段名 | 类型 | 是否主键 | 注释 | | :------------: | :-----: | :------: | :-------------------: | | userId | int | 是 | 用户编号 | | userAccount | varchar | 否 | 账号 | | userMobile | varchar | 否 | 手机号 | | userPassword | varchar | 否 | 密码 | | userCreateTime | varchar | 否 | 创建时间 | | userIdentity | varchar | 否 | 用户身份,admin和user | **tb_token**: | 字段名 | 类型 | 是否主键 | 注释 | | :--------: | :------: | :------: | :------: | | userId | int | 是 | 用户编号 | | token | varchar | 否 | token | | expireTime | datetime | 否 | 过期时间 | | updateTime | datetime | 否 | 更新时间 | **tb_log**:(日志) | 字段名 | 类型 | 是否主键 | 注释 | | :--------: | :-----: | :------: | :------------: | | logId | int | 是 | | | userId | int | 否 | 用户编号 | | operation | varchar | 否 | 用户操作 | | method | varchar | 否 | 请求方法 | | params | varchar | 否 | 请求参数 | | time | bigint | 否 | 执行时长(毫秒) | | ip | varchar | 否 | IP地址 | | createTime | varchar | 否 | 创建时间 | #### 4.2.2 goods_db 作用:商品基本信息模块所用到的数据库 **tb_goods_basis**:(商品基本信息) | 字段名 | 类型 | 是否主键 | 注释 | | :---------------: | :-----: | :------: | :------------: | | goodsId | int | 是 | 商品号 | | goodsName | varchar | 否 | 商品名 | | goodsType | varchar | 否 | 商品分类 | | goodsPrice | double | 否 | 商品单价 | | goodsStock | int | 否 | 商品库存 | | goodsIntroduction | varchar | 否 | 商品简介 | | goodsOwerId | int | 否 | 商品所属的用户 | **tb_goods_image**:(商品信息) | 字段名 | 类型 | 是否主键 | 注释 | | :-------: | :-----: | :------: | :------: | | goodsId | int | 是 | 商品号 | | imagePath | varchar | 是 | 图片路径 | **tb_log**:(日志) | 字段名 | 类型 | 是否主键 | 注释 | | :--------: | :-----: | :------: | :------------: | | logId | int | 是 | | | userId | int | 否 | 用户id | | operation | varchar | 否 | 用户操作 | | method | varchar | 否 | 请求方法 | | params | varchar | 否 | 请求参数 | | time | bigint | 否 | 执行时长(毫秒) | | ip | varchar | 否 | IP地址 | | createTime | varchar | 否 | 创建时间 | #### 4.2.3 order_db 作用:商品订单模块所用到的数据库 **tb_goods_order**:(商品订单) | 字段名 | 类型 | 是否主键 | 注释 | | :----------------: | :-----: | :------: | :------------------------------------------------: | | orderId | int | 是 | 订单编号 | | goodsId | int | 否 | 商品号 | | goddsNum | float | 否 | 商品数量 | | sellerId | int | 否 | 卖家用户编号 | | buyerId | int | 否 | 买家用户编号 | | orderState | int | 否 | 订单状态 1:未付款 2:已付款 3:已送达 4:已接收(结束) | | orderInvoleValue | float | 否 | 订单涉及金额 | | orderStartDatetime | varchar | 否 | 订单开始时间 | | orderEndDatetime | varchar | 否 | 订单结束时间 | **tb_capital**:(转账账单) | 字段名 | 类型 | 是否主键 | 注释 | | :------------------: | :-----: | :------: | :--------: | | capitalId | int | 是 | 账单id | | fromUserId | int | 否 | 转账发起者 | | toUserId | int | 否 | 转账接收者 | | transferAccountsTime | varchar | 否 | 转账时间 | | amount | float | 否 | 转账金额 | **tb_log**:(日志) | 字段名 | 类型 | 是否主键 | 注释 | | :--------: | :-----: | :------: | :------------: | | logId | int | 是 | | | userId | int | 否 | 用户id | | operation | varchar | 否 | 用户操作 | | method | varchar | 否 | 请求方法 | | params | varchar | 否 | 请求参数 | | time | bigint | 否 | 执行时长(毫秒) | | ip | varchar | 否 | IP地址 | | createTime | varchar | 否 | 创建时间 | #### 4.2.4 hb_db 作用:皇榜模块所用到的数据库 **tb_hb_basis**:(皇榜基本信息) | 字段名 | 类型 | 是否主键 | 注释 | | :-----------------------: | :-----: | :------: | :--------------: | | hbId | int | 是 | 皇榜id | | hbName | varchar | 否 | 皇榜名称 | | hbReward | float | 否 | 皇榜报酬 | | hbType | varchar | 否 | 皇榜类型 | | hbIntroduction | varchar | 否 | 皇榜简介 | | hbReleaseDatetime | varchar | 否 | 皇榜发布时间 | | hbReleaseDeadlineDatetime | varchar | 否 | 皇榜结束接收时间 | | hbFinishDeadlineDatetime | varchar | 否 | 皇榜完成时间线 | | hbReleaseUserid | int | 否 | 皇榜发布者 | **tb_hb_image**:(皇榜图片) | 字段名 | 类型 | 是否主键 | 注释 | | :-------: | :-----: | :------: | :----: | | hbId | int | 否 | 皇榜id | | imagePath | varchar | 否 | 图片id | **tb_hb_relation**:(皇榜接受者关系) | 字段名 | 类型 | 是否主键 | 注释 | | :------------: | :--: | :------: | :---------------------------------: | | hbId | int | 是 | 皇榜id | | hbAcceptUserid | int | 是 | 皇榜接受者 | | hbState | int | 否 | 皇榜状态 1:未被接 2:未完成 3:已完成 | **tb_log**:(日志) | 字段名 | 类型 | 是否主键 | 注释 | | :--------: | :-----: | :------: | :------------: | | logId | int | 是 | | | userId | int | 否 | 用户id | | operation | varchar | 否 | 用户操作 | | method | varchar | 否 | 请求方法 | | params | varchar | 否 | 请求参数 | | time | bigint | 否 | 执行时长(毫秒) | | ip | varchar | 否 | IP地址 | | createTime | varchar | 否 | 创建时间 | ### 4.3 数据库字段解释 1. 数据库保存时间点字段的类型是 **varchar** 其格式为 **yyyy-MM-dd hh:mm:ss** 2. 数据库日志表字段 **time** 其类型为 bigint 对应java中的 Long 类型 ## 5.项目规范 ### 5.1 模型篇 #### 5.1.1 数据库交互对象 跟数据库打交道的对象,一律使用PO进行结尾 跟数据库交互的对象,全部通过逆向生成工具进行生成 所有PO对象,放置在子模块dao下 所有映射生成的xml文件,在子模块dao的resources/mapper下 ### 5.2 命名篇 #### 5.2.1 项目命名 xx-xx/xx-xx-xx 项目名-模块名/项目名-模块名-二级模块名 大小写:全部小写,单词间使用-连接 #### 5.2.2 包命名 cn.hnucm.xx xx:模块名 #### 5.2.3 目录结构命名 src/main/java下 cn.hnucm.服务名.xx下有以下包 config/配置类 Xx controller/接口访问层 mapper/数据库访问层 service/业务处理层 ​ - impl/业务处理实现类 entity/数据库表对应实体类 util/工具类 #### 5.2.4 类命名 **启动类命名必须根据业务进行命名,驼峰,`Application`结尾** **`Controller`必须根据业务进行命名,驼峰,`Controller`结尾** **`Service`必须根据业务进行命名,驼峰,`Service`结尾** **`implement`必须根据业务进行命名,驼峰,业务+Service+impl结尾** **辅助类的命名,根据功能进行命名,并且以Utils进行结尾** #### 5.2.5 函数命名 函数命名使用驼峰命名 辅助函数,例如构建对象,请用build开头,表示只用于构建对象,并且返回 辅助函数,请使用private修饰 DAO层函数命名 **查询单个尽量使用queryXX或者selectXX命名** **查询多个尽量使用queryXXs或者selectXXs复数形式进行命名** **更新单个尽量使用modifyXX或者updateXX命名** **更新多个尽量使用modifyXXs或者updateXX复数形式进行命名** **插入单个尽量使用insert或者add命名** **插入多个尽量使用insertXXs或者addXXs命名** DAO所有传参如果是单个参数,请使用@param注解进行注明 #### 5.2.6 变量命名 - 使用**驼峰** - 状态类的变量,请使用int类型 - boolean类型的变量,请使用**has开头**,请勿使用is开头,在某些序列化框架下,可能会导致反序列化失败 #### 5.2.7 枚举/常量命名 - 枚举类型使用全大写,_进行分割 - 枚举命名请使用业务+Enum进行命名 - 接口常量命名请使用业务+Constant进行命名(尽量使用枚举来定义常量) ### 5.3 函数参数篇 #### 5.3.1 接口参数 - **尽量使用对象进行传递**,严禁使用MAP进行传参 - 如果要进行单个参数传递,最好不要操作5个参数,参数太多,看起来太混乱 #### 5.3.2 辅助函数参数 - 尽量使用对象进行传参,严禁使用Map进行传参 - 如果要进行单个参数传递,最好不要操作5个参数,参数太多,看起来太混乱 ### 5.4 注释篇 #### 5.4.1 类注释 ``` /** * @author: 作者 * @Description: 类作用描述 * @Date: 创建时间 */ ``` #### 5.4.2 函数注释 函数参数,一定要加上 @param 这样,别人在调用的时候,idea会进行提示,如果涉及到枚举 加上注解 @see 可以跳转到枚举 ``` /** * 创建人:XXX * 创建时间:2021-11-11 20:46:04 * 描述: 购物车创建订单 * @param userId 用户ID * @param subUserId 用户ID * @param addrId 地址ID * @param cartProductIds 购物车ID集合 * @param fahuoTimeLimitedMode 截单模式 0 立即截单, 1 根据活动时间截单 */ ``` #### 5.4.3 代码注释 代码注释,进行别使用/**/的形式,注释不需要像写作文那样详细,只需要介绍是做什么的就好 ``` // 构建订单对象 ``` ### 5.5 其它篇 代码是逻辑的表现,一段代码是否是好代码,主要是要看逻辑是否清晰,因为业务代码是给人看的,并不是框架或者开源代码,写的太高大上,各种设计模式,并非好事,有过度设计的嫌疑,尽量做到面向接口编程,提高内聚,降低耦合 #### 5.5.1 代码 - `Controller`尽量只做转发,不做具体逻辑实现,所有逻辑实现交由service进行 - service的接口函数,尽量功能单一,职责越小,越便于维护跟扩展 - **如果涉及到写等动作,请在函数上加上@transaction注解**/或者自己用事务块包裹 - service如果不需要捕获异常,可以往上层抛,订单中心已经在**全局做了异常处理** - 尽量做到所有的check在入参就应该进行判断 - 如果遇到需要构建对象,大量 set函数不应该放置主流程,抽离出来一个辅助函数,直接调用辅助函数即可,辅助函数注释写好,主流程调用辅助函数加上功能注释 - 代码内部尽量不使用多层for循环调用,在不注意的情况,多层for循环嵌套构建对象,很容易写出内存泄漏的代码 - **尽量不使用匿名内部类,使用lambda**,因为现在jdk已经是1.8版本,支持Java8的特性 - 如果一段代码,超过两个地方调用,说明需要进行抽象,然后对抽象进行实现 - 函数跳转层级尽量不要过深,因为是业务代码,跳转太深,很容易把人绕晕了 - 如果一个函数**出现特别多的if else 考虑把if else建成枚举,**然后枚举内进行判断返回 #### 5.5.2 日志 - 所有service层可以直接抛出异常,不需要捕获异常处理,已经配置好全局异常处理,只需要抛出错误信息就好 - 业务错误打印日志,尽量别打印error打印warning级别日志就好,所有抛出异常上面,尽量打印错误日志的参数 - 日志打印,尽量使用一下示例打印 // 正确打印 LOGGER.info("订单ID错误,订单ID:{}",order.getId()); // 错误打印 LOGGER.info("订单ID错误,订单ID:"+order.getId()); - 日志是常量,所以请使用以下定义 private static finale Logger LOGGER = LoggerFactory.get(XX.class); - 日志引用,禁止引用具体实现,请引用 slf4j接口 #### 5.5.3 请求路径 - 尽量使用Restful风格 - /liveId/productId URL参数,请使用 @PathVariable("liveId")String liveId 指定名称绑定 - 查询尽量使用Get请求方式,如果参数在URL传递过多,可以不使用Get请求,使用POST请求,请把参数写进请求体内 - 所有**写的操作一律使用POST请求**,参数放入请求体内,公共参数,以后会让客户端放入请求头内 #### 5.5.4 幂等 - 所有的核心写接口,例如,创建订单,支付,取消订单等,一定一定要做幂等,幂等可以在所有的check后也可以在函数调用就进行判断,但是一定是在逻辑进行前 - 幂等接口,一定要跟调用方统一状态,达成共识 - 往往幂等会伴随着并发同时进行,因为网络传输,机器性能,请求处理,事务提交带有太多的不确定性,所以要加以控制,所以redis尽量只做并发控制跟短时间内的幂等,请勿太依赖redis来进行做幂等,在redis锁后,插入前请进行DB查询操作,查看是否已经写入过,如果已经写入,拒绝请求 #### 5.5.5 锁 单机锁,如果没有竞争资源,不要使用锁 尽量使用 Lock接口作为锁,别使用Synchronize作为锁,后者作为重量级锁,太影响性能 对锁的使用不清楚,严禁私自使用,尽量多请教会的人,避免写出死锁或者活锁 分布式锁,目前只是用了redis的setnx操作作为分布式锁的实现,使用分布式锁,一定要设置过期时间或者在锁代码块执行完毕,手动移除锁 目前setnx操作,使用的是jedis连接池来实现的,没有使用spring-data提供的redisTemplate是因为,后者的setnx操作并非一个原子操作,运气不好的情况,极有可能出现setnx操作了,setexprie失败,导致锁不过期,但是jedis使用,切勿忘记,使用完毕,归还连接,jedis是不会再你调用完毕主动归还连接的 所有锁,请在check完毕或者check之前进行锁定资源,请勿在最后锁定,进行无用的写 锁定的资源,必须是唯一的,例如,订单ID,订单编号等