# leyimall **Repository Path**: liuhedev/leyimall ## Basic Information - **Project Name**: leyimall - **Description**: leyi mall - **Primary Language**: Java - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-06-16 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # leyimall #### 介绍 乐一商城 day8-FastDFS及ngnix配置 day11-elasticsearch day14-GoodsApi 返回值为啥没有ResponseEntity? #### 软件架构 商品相关内容, - leyou-item-interface:主要是对外暴露的接口及相关实体类 - leyou-item-service:所有业务逻辑及内部使用接口 1、测试路由规则,在不用些control的情况,引入此依赖,即可在eureka web页面点击链接测试连通性 spring-boot-starter-actuator 2、zuul部署上之后,Zuul中默认就已经集成了Ribbon负载均衡和Hystrix熔断机制。但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。错误信息:o.s.c.n.z.filters.post.SendErrorFilter : Error during filtering 3、com.github.pagehelper.PageHelper PageHelper拦截的是org.apache.ibatis.executor.Executor的query方法,其传参的核心原理是通过ThreadLocal进行的, 当我们需要对某个查询进行分页查询时,我们可以再调用Mapper进行查询前调用一次PagerHelper.startPage(),这样PagerHelper会把分页信息存入ThreadLocal变量中。在拦截到Executor的query方法时则会从对应的ThreadLocal中获取分页信息,获取到了以后,则进行分页处理,处理完成后会把ThreadLocal中的分页信息处理掉,以便不影响下一次的查询操作。 4、Slf4j+logback/log4j2 slf4j:Simple Logging Facade for Java ``` ribbon: ReadTimeout: 60000 ConnectTimeout: 60000 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 60000 ``` 5、依赖注入的方式 依赖注入有三种方式: ``` (1)变量(filed)注入 优点:简洁、 (2)构造器注入 (3)set方法注入 ``` 6、图片上传说明 图片上传是文件的传输,如果也经过Zuul网关的代理,文件就会经过多次网路传输,造成不必要的网络负担。在高并发时,可能导致网络阻塞,Zuul网关不可用。这样我们的整个系统就瘫痪了。 7、商品规格设计 数据库设计: ``` //商品规格信息,同一spu,规格类型基本一致 // 规格参数分组表 create table `t_spec_group` ( `id` bigint(20) not null auto_increment comment '主键', `cid` bigint(20) not null comment ’商品分类id,一个分类下有多个规格组‘, `name` varchar(50) not null commect '规格组名称', primary key(`id`), key `key_category`(`cid`) ) charset=utf8 comment='规格参数的分组表,每个商品分类下有多个规格参数组'; // 规格参数表 CREATE TABLE `tb_spec_param` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `cid` bigint(20) NOT NULL COMMENT '商品分类id', `group_id` bigint(20) NOT NULL, `name` varchar(255) NOT NULL COMMENT '参数名', `numeric` tinyint(1) NOT NULL COMMENT '是否是数字类型参数,true或false', `unit` varchar(255) DEFAULT '' COMMENT '数字类型参数的单位,非数字类型可以为空', `generic` tinyint(1) NOT NULL COMMENT '是否是sku通用属性,true或false', `searching` tinyint(1) NOT NULL COMMENT '是否用于搜索过滤,true或false', `segments` varchar(1000) DEFAULT '' COMMENT '数值类型参数,如果需要搜索,则添加分段间隔值,如CPU频率间隔:0.5-1.0', PRIMARY KEY (`id`), KEY `key_group` (`group_id`), KEY `key_category` (`cid`) ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='规格参数组下的参数名'; // spu表 create table `t_spu`( `id` bigint(20) not null auto_increment comment 'spu id', `title` varchar(128) not null default '' comment '标题', `sub_title` varchar(256) not null default '' comment '副标题', `cid1` bigint(20) not null comment '1级类目id', 'cid2' bigint(20) not null comment '2级类目id', `cid3` bigint(20) not null comment '3级类目id', `saleable` tinyint(1) not null default '1' comment '是否上架:0下架,1上架', `valid` tinyint(1) not null default '1' comment '是否有效,0已删除,1有效', `create_time` datetime default null comment '添加时间', `last_update_time` datetime default null comment '最后更新时间', primary key(`id`) ) charset=utf8 comment='spu表'; // spu detail表 因为spu表数据量比较大,所以对spu表做了垂直拆分,将spu的详情信息放到t_spu_detail表中 CREATE TABLE `tb_spu_detail` ( `spu_id` bigint(20) NOT NULL, `description` text COMMENT '商品描述信息', `generic_spec` varchar(10000) NOT NULL DEFAULT '' COMMENT '通用规格参数数据', `special_spec` varchar(1000) NOT NULL COMMENT '特有规格参数及可选值信息,json格式', `packing_list` varchar(3000) DEFAULT '' COMMENT '包装清单', `after_service` varchar(3000) DEFAULT '' COMMENT '售后服务', PRIMARY KEY (`spu_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 comment 'spu详情页及规格选择数据'; // sku表 indexs设计,方便通过角标快速定位到sku。 CREATE TABLE `tb_sku` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'sku id', `spu_id` bigint(20) NOT NULL COMMENT 'spu id', `title` varchar(255) NOT NULL COMMENT '商品标题', `images` varchar(1000) DEFAULT '' COMMENT '商品的图片,多个图片以‘,’分割', `price` bigint(15) NOT NULL DEFAULT '0' COMMENT '销售价格,单位为分', `indexes` varchar(100) COMMENT '特有规格属性在spu属性模板中的对应下标组合', `own_spec` varchar(1000) COMMENT 'sku的特有规格参数,json格式', `enable` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否有效,0无效,1有效', `create_time` datetime NOT NULL COMMENT '添加时间', `last_update_time` datetime NOT NULL COMMENT '最后修改时间', PRIMARY KEY (`id`), KEY `key_spu_id` (`spu_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='sku表,该表表示具体的商品实体,如黑色的64GB的iphone 8'; // 库存 因为库存字段写频率较高,而sku的其他字段以读为主,因此我们将两个表分离,读写不会干扰。 CREATE TABLE `tb_stock` ( `sku_id` bigint(20) NOT NULL COMMENT '库存对应的商品sku id', `seckill_stock` int(9) DEFAULT '0' COMMENT '可秒杀库存', `seckill_total` int(9) DEFAULT '0' COMMENT '秒杀总数量', `stock` int(9) NOT NULL COMMENT '库存数量', PRIMARY KEY (`sku_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='库存表,代表库存,秒杀库存等信息'; ``` 7、java中常用概念 do: data object po:persistant object持久对象, bean,entity等命名; bo:business object业务对象, service、manage、business等命名; vo:value object值对象,主要体现在视图的对象; dto: Data transfer object数据传输对象,经过处理后的po,可能增加或者减少po的属性; pojo:plan ordinary java object简单java对象,即pojo是一个简单的java对象,他不包含业务逻辑或持久逻辑等,但不是JavaBean、EntityBean等,不具有任何特殊角色和不继承或者不实现任何其它Java框架的类或接口。 8、tk mybatis实体字段存在关键字、保留字,执行报错 ``` The error occurred while setting parameters ### SQL: SELECT id,cid,group_id,name,numeric,unit,generic,searching,segments FROM tb_spec_param WHERE cid = ? ### ``` 其中,numeric为保留字,解决方案为持久化对象中使用@Column("`numeric`")标注一下。 9、@Transactional的使用 Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。 使用@Transactional的相比传统的我们需要手动开启事务,然后提交事务来说。它提供如下方便 - 根据你的配置,设置是否自动开启事务 - 自动提交事务或者遇到异常自动回滚 ``` @Service public class StudentService { @Autowired StudentDao studentDao; @Transactional public void innerSave(int i) { Student student = new Student(); student.setName("test" + i); studentDao.save(student); //i=5 会出现异常 int a = 1 / (i - 5); } } ``` 10、@Transient @Transient表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性; 如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则ORM框架默认其注解为@Basic; ``` public class SkuDo { private Long id; // skuId @Transient private Integer stock;// 库存 } ``` @JsonIgnore 作用:在json序列化时将pojo中的一些属性忽略掉,标记在属性或者方法上,返回的json数据即不包含该属性。 ``` com.fasterxml.jackson.core jackson-annotations compile ``` 11、理解JPA注解 - @Entity : 表示该类是一个实体,也就是和表形成映射,可以添加属性来指定对应的表 ​ 如:@Entity(name="t_user") - @Table : 指定表名,非必须填写,可以在entity注解上直接表示表名。但是@Table 就是改变某些默认的映射规则,如表名,schema等,可以添加索引和约束,看一下它的定义 ​ 如 : @Table(name="t_user") - @Id : 用于表示主键,指定哪一个属性和主键对应 可以在变量上声明,也可以在get方法上声明,建议统一。 - @GeneratedValue : 用于表示主键生成策略 主键生成策略,提供的有4种 @Entity可以和@Table一起使用,但是@Table设置的优先级较高。 ``` 1、AUTO 自动选择一个最适合底层数据库的主键生成策略。如MySQL会自动对应auto increment。这个是默认选项,即如果只写@GeneratedValue,等价于@GeneratedValue(strategy=GenerationType.AUTO)。注意在mysql5 + hibernate 5的版本测试下,会产生另外一张表,用于记录主键值。 可以在核心配资文件中添加此属性来达到native效果 false 2、IDENTITY 表自增长字段,Oracle不支持这种方式。 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; 3、SEQUENCE 通过序列产生主键,MySQL不支持这种方式。 4、TABLE 通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。不同的JPA实现商生成的表名是不同的,如 OpenJPA生成openjpa_sequence_table表,Hibernate生成一个hibernate_sequences表,而TopLink则生成sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME和SEQ_COUNT。 ``` 以上,测试发现@Entity在配合tx.mybatis使用的时候,设置的表名不生效,依然默认使用类名小写。 12、Java8 .stream() .map() .collect()用法 ``` mylist.stream() .map(fun->{ return item; }).collection(Collection.toList()); ``` stream(流)是一个来自数据源的元素队列并支持聚合操作。 * 聚合操作:类似于sql语句一样的操作,比如filter\map\reduce\find\match\sorted等。 stream的基本步骤:( (1)创建stream (2)中间操作:转换stream,每次转换原stream对象不改变,返回一个新的stream对象(可以有多次转换) (3)结束操作:对stream进行聚合(reduce)操作,获取想要的结果。 ![stream](./documents/stream.png) 参考:https://zhuanlan.zhihu.com/p/94882031 13、spring-boot-starter-data-jpa和mybatis Spring Data JPA与MyBatis对比,起始也就是hibernate与MyBatis对比。所以,我们直接来比较后两者。 * JPA是一个规范,而不是框架 * Hibernate是JPA的一种实现,是一个框架 * Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,底层使用hibernate。 * MyBatis不是JPA体系,需要写sql语句,它是半自动ORM框架 14、hibernate.validator