如何完成Goods查询页面(使用Map进行键值对的传入来编写规格参数,StringUtils的分割符用法,json对象的序列化和反序列化,)

我们下面来说一下如何把List<spu>转换成List<Goods>

首先我们要清楚一个问题,就是为什么我们要把spu转换成goods?因为我们在日常的开发当中,我们所用的查询方法是索引查询方法,索引查询方法是更加高效更加快速的,所以我们先要把索引和字段整理成一个goods实体类,然后再去接收spu这个json参数,一个个去把里面的值赋予goods实体类,这里说一下大概思路,就是我们需要建立一个查询模块,然后让商品微服务提供一个接口到接口类,之后我们就要在查询模块里面去继承这个接口类,来自己去使用。这里有个问题,从前端传过来的spu我们该如何去获取,这就涉及RequestMapping方法了。

好了,接下来让我们慢慢去实现它。

首先我们要去新建一个SearchService,为什么要新建这个呢?因为我们要编写对应的查询微服务的业务逻辑。
在这里插入图片描述

首先我们需要声明它是一个Service,打上这个注解,因为无论你是什么页面,只要是Service,就要打上这个注解,其次我们要在里面写什么样的方法呢?首先你要明确思路,你要在这个Service里面做什么事情,我们要做的事情就是把spu转换为Goods,这就是我们要做的事情, 具体该怎么操作呢?首先你要一个个把spu的数据传入到Goods里面,像id,cid1,cid2,cid3,BrandId(品牌id),CreateTime(创建时间),SubTitle(副标题)这些我们都可以直接用set方法直接传进Goods里面,因为他们都只是一次一条的信息,而不是一个List。

还需要注意的是要传入All字段,为什么要写上这个All?在Goods方法里面我们已经封装了这个All方法了,这里面就是用户搜索关键词的方法,也就是说用户只要搜索到All里面任何一个字段,他就能成功获取有这个关键词的全部商品信息。可以看到这里我们的All里面有两个null,这里只是暂时这么写的,因为我们还要把商品分类还有品牌传进去,但是为什么不能直接传入它们的get方法呢?
因为你可以看到我们这里的goods的set方法它只是一条信息而不是List,这说明什么,说明All它只是一行的字,这一行的字中有标题,分类信息,还有品牌名组合而成,但是也就是说标题我们可以直接去获取到了,毕竟在spu当中我们直接就有这个信息,其余的像分类信息和品牌信息我们却不能直接获取到,下面我放了spu实体类的图片,可以去看看
在这里插入图片描述
可以看到下面就是spu的实体类
在这里插入图片描述
下面的这个Transient注解表示这个不是数据库里面的属性名,它只是临时被添加进去的
在这里插入图片描述

可以看看下图中的Goods实体类信息里,All表示所有要被用户搜索到的字段。
这里说一下下面的这个Data注解,是需要你引入lombok的jar包之后你才能用这个注解,这个注解的作用就是一般我们实体类都需要写get和set方法,但是如果你引入了这个Data注解后,你就不需要写get或者set方法或者toString,Data会自动生成。
Document这个注解表示的是建立索引库,并且为索引库取名为什么(这里为goods),type就是数据表,shards就是分片,replicas就是副片。
下面的信息当中,如果有加注释说明就是一个字段,也有注明是否为索引,如果没有加注释就不是一个字段更加没索引,那么哪些应该加字段哪些不应该加呢?首先id是不用加的,没有人会直接搜索id吧?用户搜索的都是标题,商品属性,或者分类品牌等等,当然卖点也是用户搜索的东西。在这里插入图片描述
好了,回到正题上,我们还需要加上下面的属性,一个是Price,这个Price是哪里的属性呢?Price是Sku的属性,为什么这里我们也是暂时给不出这个值呢?,可以看看上面我们的spu实体类里面并没有Price这个属性名,这个属性名是在Sku里面的,我们这里是一个spu,但是你要知道一个spu是对应多个spu的,因为你选择了一个手机商品,它可能因为内存的不同(有些64G,有些128G),而影响到价格的不一样,所以我们一个spu对应的Price有很多个,这个Price是个集合。,还有我们要获取所有的sku,并且转换为json字符串,还有获取规格参数。这里有个问题,我们获取所有的sku不就等于获取了所有的价格和规格参数等信息了吗,为什么还要单独把价格和规格参数写出来。

这是因为价格和规格参数最终也是要做成一个集合的,因为用户在搜索到一堆商品信息后,想要通过筛选来决定哪些商品的价格是合适的,还有就是哪些商品的规格参数是合适的,所以我们要单独做出来让商家得到参考。

在这里插入图片描述

可以看到我们规格参数的这一块,你传入的name也就是value,Goods方法中是一个键,也就是说你传入的是一个键,
在这里插入图片描述

在这里插入图片描述
根据规格参数的这个key值我们就可以进行聚合,这个Map键值对的意思就是输入一个关键词Key,然后会返回很多个类型,有Long,String等等类型,为了方便我们直接用Object就可以了。
在这里插入图片描述
聚合后的结果就会放在这里然后供大家进行选择,比如颜色是红色,黄色等等
在这里插入图片描述
看到下面这里,我们需要分类名称来编写all字段,所以我们先要获取分类名称,那这里就有个问题,我们该如何去根据三个分类id来获取一条分类名称呢?我们需要先找到三个分类id对应的名称,然后把这三个名称整合成一条名称,所以需要用到根据分类id查询到分类名称的方法,因为我们需要把三个cid的参数作为List传进去,可以直接用Arrays.asList方法把它们变成一个List集合,然后传进来。

在此之前要封装商品分类的接口方法,因为我们要调用这个查询方法。

我们最后是获取到了一个查询到商品分类名称names的List列表,但是我们该如何传进去只有一条文字的all方法里面呢?
在这里插入图片描述
我们可以用StringUtils里面的join方法进行改变,第一个参数就是一个集合,我们把names集合传进去,第二个参数就是一个分隔符,我们用空格进行分隔,然后传进去就可以了。

在这里插入图片描述

接下来我们还有个品牌名字没有拿到,要想拿到品牌名字首先要有品牌id,通过品牌id去找到品牌名字,所以我们需要引进通过品牌id查询品牌名称的接口,顺便把其他需要的接口先引进来。
在这里插入图片描述
因为我们获取到的品牌信息只是一条信息,所以直接用Brand作为返回值,这里顺便解释一下为什么用this,this表示在当前页面下的方法,所以就可以用this来直接调用品牌brand查询方法。

因为我们的品牌id已经在spu里面被接收到了,所以我们可以直接拿品牌id过来然后获取它的名字。可能有人会说,我传进去一个id,获得的不是一个字符串吗,直接用String作为返回值不可以吗?但是你要知道,你传进去一个id,获得的是整个Brand的信息,所以需要用Brand作为返回值,String并没有接收这个返回参数的能力,因为Brand里面除了有id,还有品牌名称,品牌图片等等信息,下面附上Brand实体类图。

在这里插入图片描述
在这里插入图片描述
然后我们再来看这里,如果要获取所有的价格,我们该从哪里进行获取呢?首先这个价格是什么概念,我们这里只是传了一个spu,也就是只有一个goods,一个spu里面有多个sku,每个sku都有一个特定的价格,所以我们现在要做的,就是获取这所有的价格。要获取这所有的价格,我们必须先获取所有的sku先。那我们该如何获取所有的sku呢?获取到的sku肯定是个List,我们该如何接收?
在这里插入图片描述
我们要去根据spu的id去获取所有的sku的信息,为什么我们要使用spu的id去获取所有的sku信息呢?难道一条spu的id就可以查到所有sku的信息?因为我之前的一篇博客就写到过这个数据库表的spu和sku的对应信息,一个spu的id在sku的表里面是对应多个sku的,所以

在这里插入图片描述
我们得到所有sku的集合后,那该如何把每个sku里面的价格拿出来呢?首先我们就可以先定义一个List,这个是Price价格的List,右边该怎么写呢?如果你单纯只是初始化它,也就是定义一个空的List方便接收数据,你可以在右边写new ArraysList然后传入一个空的泛型,然后(),左边那里泛型为什么为Long呢?因为数据类型为数字,价格就是数字。

然后我们就需要用到遍历的方法,把skus这个集合里面的每一个sku的价格传进去这个Price集合里面,
在这里插入图片描述
最终我就可以把Prices放进来了
在这里插入图片描述
再来看看这个,我们要去实现这个功能,也就是把所有的sku转换为一个json对象,首先为什么我们要去把sku转换为一个json对象呢?因为我们当前做的是索引查询商品信息,当用户输入对应的信息搜索商品的时候,我们要返回一个结果集给用户,在当前的页面下就要显示出几个商品的信息给用户看,可能你们看不太懂我这个解释,我下面附上一张页面图给你们看。

在这里插入图片描述
这就是用户搜索到的结果,我们在当前这个页面当中每个手机商品的信息都需要加上一些sku的信息,比如价格,颜色的选择,还有一些简述。所以我们需要返回一个json对象回去给这个页面。
在这里插入图片描述

可以看到我们的sku数据表,有这么多个字段在,外面的公司肯定不止这么多字段,几百甚至上千都有,那我们需要全部都用到吗?并不需要,因为我们的前台页面只显示几个sku的信息,没必要全部都加进去,所以我们只需要拿我们需要的部分就可以了,比如id,价格,商品标题,图片。

在这里插入图片描述
我们总共只要四个值而已,这四个值都在数据表里面,我们该如何只拿到这四个值?

下面我们就可以用键值对的方法去获取这四个值。
在这里插入图片描述

如果要获取那四个值,我们需要做什么呢?首先我们需要初始化一个键值对的方法,这里传进去的泛型的Map键值对为什么是String和Object呢?因为你所要的四个值,其实也是一个String类型的,所以我们可以用String类型去接收所有。

在下面遍历的方法当中,我们首先new一个HashMap,因为我们要使用键值对,所以必须先new一个HashMap才能使用,在下图中的上面的那个不是new HashMap而是初始化一个List而已。

new完这个HashMap后我们就要开始传键值对进去了,把id,title,price,还有图片传进去,这里的键值对就是一个json对象,所以你不用List来返回这个Map,出来外面后才需要而已。

这里重点说一下图片的键值对传法,因为我们这个图片你可以到数据表里面看看,一个sku是有可能对应多个图片的,这个是什么意思呢?也就是你一个有具体参数的产品比如红色手机64G,这个是很具体的参数了,它可能有两个或者三个以上的图片,那我们应该如何把它传进键值对里面去呢?所以我们就要用StringUtils去判断了,如果为空,就返回一个空格,如果不为空,就用StringUtils的分割方法,把这几个图片进行分割。

这里可能有人会问,sku.getImages返回的不是一个List集合吗?为什么它不用List来接收,因为在StringUtils.split这个分割方法当中,你只需要传入sku.getImages,它自动会把你分成一个List,然后用后面的字符把你们进行分割,这里用的是“,”进行分割,分割完后,它自动把你们列为一个数组,我们只需要获取数组里面的一个图片就够了,所以用第【0】这个子集,所以这整个就是一个值。
在这里插入图片描述
最终我们用add方法就可以了(List里面有add方法)

在这里插入图片描述

传好了之后,我们就可以放进下面的这个Skus里面作为一个json对象,但是有个问题。
在这里插入图片描述
这个set方法接收的是字符串,但是我们得到的是一个List集合的键值对。怎么把这个List转换成json字符串呢?
在这里插入图片描述
所以我们要用到json工具来进行转换。

在这里插入图片描述
可以看到这个方法可以把对象转换成json对象,并且返回的是String类型的。
在这里插入图片描述
如果你要反过来进行转换,可以用这个方法,还可以选择你想要转换出来的类型是什么
在这里插入图片描述
然后我们直接把skuMapList传进去,如果有异常,直接抛出就好。
在这里插入图片描述

然后到了最后一个了,我们需要获取所有的规格参数。这个规格参数是显示在哪里的呢?
在这里插入图片描述
这个就是你要获取的规格参数页面,你要得到这些参数,你首先要有个方法去查询到这些参数是什么,因为这些参数的获得跟你选择的分类有关。
在这里插入图片描述
我们可以看看下面这个数据表,我们要根据cid来判断是否有searching的值给你去显示,searching为true,这个参数才会被显示,反之就不显示。那么为什么我们不同其他的id来匹配searching?因为规格参数是根据分类来决定的,可以从浏览器页面看出来,你点击一个分类,就会显示不同的规格参数。
在这里插入图片描述
我们该如何根据分类id获取规格参数呢?之前我们写过了这个根据分类id获取参数的queryParams方法,因为我们只需要通过分类id来获取规格参数,并不用传入具体的规格参数id或者写入是否通用。所以我们这里直接传入分类id和传入searching是否为true即可。有人可能会有疑问,我直接传入searching等于true,数据库自己会进行判断吗?
在这里插入图片描述
看到我们这个querySpecParamList方法(其实也就是queryParams方法,只是后来改了名字而已),这个方法就是把传进来的cid和searching有传给了Service里面的querySpecParamList方法里
在这里插入图片描述
在Service方法里,接收到了cid为一个数字和searching为true,我们把它传进了param里面,并且传入了Mapper方法进行在数据库的搜寻,符合cid为这个数字和searching为true这个条件的数据将会返回一个List列表,如果内容为空,就会抛出,如果不为空,则返回这个List。
在这里插入图片描述
所以回到这里来,我们就都已经拿到规格参数了。
在这里插入图片描述
然而我们的最终目的是把它封装成一个参数名和值的一个结构,该怎么去完成呢?
在这里插入图片描述
首先我们来分析一下数据库,可能有人会说,我要参数名和对应的值,和数据库有什么关系?因为我们目前已经得到了所有的规格参数信息,然而获取参数名和它的规格参数是和数据库有关的,我们还是要先看看数据库是怎么编写的。

可以看到下面规格参数的这个数据表里面,name就是我们要获取的一个参数名,但是我们的规格参数从哪里来呢?有人会误以为右边的就是规格参数,但你们没有发现很奇怪吗,右边数值那里不是0就是1,所以右边的并不是规格参数,它只是判断你是否启用单位而已,1代表true也就是启用后面的这个单位,0代表没有单位
在这里插入图片描述

我们可以看到,我们想要的规格参数都在这个数据表里面,而且它的1,2,3等等分别代表了上图中的Param的id。但是可以看到,它把这些参数名和对应的规格参数写到了一起,成为了一个json对象,我们该如何从这个字符串json对象里面去获取我们所要的参数名和规格参数呢?很简单,我们可以用反序列化转换的方法。
在这里插入图片描述
所以看看上图当中,我们要把这个规格参数反序列化,首先要获取这个规格参数的json的唯一标识,从上图可以看出唯一标识就是spu的id,刚好我们也获得了这个spu,先通过spu的id查询到对应的spu_detail全部信息,找到了当前那一条信息后,我们就要开始操作反序列化了,但是如果是反序列化,最终转换为什么类型的结果呢?看看上面的数据,是不是有点像键值对,所以我们最后要转换为Map结果。

首先调用json工具MAPPER进行反序列化,传入你要反序列化的对象,也就是getGenericSpec,然后选择你要转换成为的类型,这里用到转换工具接口TypeReference,在这里new了一个,然后把转换的类型Map传进去了,最后别忘了花括号,因为这是一个接口方法。
有人可能会问,我转换为键值对后有这么多个键值对,但是返回值为什么不是List而是Map,因为你所有都是键值对,所以用Map做返回值一次就可以接收多个键值对了,不需要List。

在这里插入图片描述
再来看看这个数据表,虽然我们上面已经把商品的规格参数反序列化了,但是商品的规格参数不是全部都有,还有一些是特殊的商品规格参数,看下图中的这个属性是是否通用的属性,值为0的即为商品不通用。那么如果是特殊商品规格参数,我们该如何获取呢?

在这里插入图片描述
我们可以看到,在sku这个表里面有特殊商品属性信息,但是这些商品只有每个属性只对应一个值,不太好搜索。
在这里插入图片描述
然而在我们这个表里面也有特殊字段,而且每个属性对应多个关键词,被搜索到的范围比较广,所以优先采用这个。注意看下面那里的对应关系,是一个String类型的属性名对应一个List类型的String或者Long类型,所以后面那个我们直接用List的Object来代替即可。
在这里插入图片描述

然后我们再进行把这个特殊的搜索字段进行和上面一样的反序列化,不同的是后面的是List
在这里插入图片描述

但别忘了,我们最终是要把上面的这些转换为一个名字加值的形式传进去,该怎么做呢?
在这里插入图片描述
可以看到这里,我们的Goods实体类里面的这个也就是上图中setSpecs相关的封装方法,这说明你肯定要传进来一个Map的键值对才行,如果你要传进来一个键值对,首先你要变成一个键值对。

在这里插入图片描述

所以我们要用这个查询到的规格参数List来进行一个个传数据和属性名形成键值对

在这里插入图片描述
键值对关键一点就是new一个HashMap,然后进行遍历,先进行判断这个规格参数是否为通用属性,如果是通用的,就得到它的值并且返回一个String,再传入Map,这里要注意要去判断它的最后拿来的值是不是一个数值,如果是数值,就要判断区间。这里注意一点,String方法右边部分对应的是Map键值对的值,它的方法解读起来就是先获取id,然后把获得的id转换为String再传入外面方法中得到一个值,最终再把值转换为String类型。

下面不通用的方法当中为什么返回值是List呢?因为上面specialSpecMap那个特殊字段Map方法返回值是个List,因为特殊字段一个属性对应多个值。
在这里插入图片描述
以下是区间判断方法,没写全,要看去网上搜

在这里插入图片描述

一般而言,可以通过以下步骤来实现联动查询: 1. 根据传入的level参数确定当前查询的表和列; 2. 根据传入的parent参数确定当前查询的条件; 3. 构造 SQL 语句,并执行查询操作,获取结果; 4. 将结果返回给前端。 具体实现可以参考以下代码示例: ```java @RequestMapping("/option/{tableName}/{columnName}") public R getOption(@PathVariable("tableName") String tableName, @PathVariable("columnName") String columnName, String level, String parent) { Map<String, Object> params = new HashMap<String, Object>(); params.put("table", tableName); params.put("column", columnName); if (StringUtils.isNotBlank(level)) { params.put("level", level); } if (StringUtils.isNotBlank(parent)) { params.put("parent", parent); } List<String> data = commonService.getOption(params); return R.ok().put("data", data); } public List<String> getOption(Map<String, Object> params) { String tableName = (String) params.get("table"); String columnName = (String) params.get("column"); String level = (String) params.get("level"); String parent = (String) params.get("parent"); // 构造 SQL 语句 StringBuilder sql = new StringBuilder(); sql.append("SELECT DISTINCT ").append(columnName).append(" FROM ").append(tableName); if (StringUtils.isNotBlank(parent)) { // 如果有父级选项,则加入查询条件 sql.append(" WHERE parent = '").append(parent).append("'"); } if (StringUtils.isNotBlank(level)) { // 如果有级别参数,则加入查询条件 if (StringUtils.isNotBlank(parent)) { sql.append(" AND "); } else { sql.append(" WHERE "); } sql.append("level = ").append(level); } // 执行查询操作,获取结果 List<String> data = jdbcTemplate.queryForList(sql.toString(), String.class); return data; } ``` 在这个示例中,我们首先通过传入参数构造查询条件,然后根据条件构造 SQL 语句,最后通过 jdbcTemplate 调用 queryForList() 方法执行查询操作,获取结果并返回。在 SQL 语句中,我们使用了 WHERE 子句来加入查询条件,如果有多个条件,则使用 AND 连接。此外,我们还使用了 DISTINCT 关键字来去重,保证返回的结果不重复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值