商品详情页,简单说就是以购物者的角度展现一个sku的详情信息。
用户点击不同的销售属性值切换不同的商品
点击添加购物车,将商品放入购物车列表中
Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。类似JSP,Velocity,FreeMaker等, 它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。与其它模板引擎相比, Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用!
项目创建,依赖模块web,Thymeleaf.模板。
就想Jsp的<%@Page %>一样 ,Thymeleaf的也要引入标签规范。不加这个虽然不影响程序运行,但是你的idea会认不出标签,不方便开发。
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
request.setAttribute("name","刘德华");
<p th:text="’hello’ + ${name}" th:value="${name}">p>
List<String> list = Arrays.asList("郑爽", "刘德华", "张惠妹", "成龙");
request.setAttribute("arrayList",list);
<table>
<tr th:each="s,stat: ${arrayList}">
<td th:text="${s}">td>
<td th:text="${stat.index}">td>
<td th:text="${stat.count}">td>
<td th:text="${stat.size}">td>
<td th:text="${stat.even}">td>
<td th:text="${stat.odd}">td>
<td th:text="${stat.first}">td>
<td th:text="${stat.last}">td>
tr>
table>
stat 称作状态变量,属性有
index:当前迭代对象的 index(从 0 开始计算)
count:当前迭代对象的 index(从 1 开始计算)
size:被迭代对象的大小
even/odd:布尔值,当前循环是否是偶数/奇数
first:布尔值,当前循环是否是第一个
last:布尔值,当前循环是否是最后一个
th:if 条件成立显示
th:unless 条件不成立的时候才会显示内容
model.addAttribute("age",18);
<h2>判断 ifh2>
<div th:if="${age}>=18" th:text="success">gooddiv>
<a th:unless="${age != 18}" th:text="success" >atguigua>
<h2>判断 三元h2>
<div th:text="${age}>=18?'success':'failure'">div>
httpSession.setAttribute("addr","北京中南海");
<div th:text="${session.addr}"> div>
<div th:include="itemInner"/>
th:utext:识别html中的标签
request.setAttribute("gname","<span style=color:green>绿色span>");
<p th:utext="${gname}">colorp>
点我带你飞
@RequestMapping("list.html")
@ResponseBody
public String list(String category1Id){
// 接收传递过来的数据
System.out.println("获取到的数据:\t"+category1Id);
return category1Id;
}
在index 控制器中先存储一个category1Id
/*保存 category1Id*/
request.setAttribute("category1Id","2");
model.addAttribute("addr","北京昌平区");
hashMap.put("id","101");
HashMap<String, Object> map = new HashMap<>();
map.put("stuNo","1000");
map.put("stuName","张三");
model.addAllAttributes(map);
<h2> 多种方式存储数据1 h2>
<div th:text="${addr}">div>
<div th:text="${id}">div>
<h2> 多种方式存储数据2 h2>
<div th:text="${stuNo}">div>
<div th:text="${stuName}">div>
商品详情所需构建的数据如下:
1,Sku基本信息
2,Sku图片信息
3,Sku分类信息
4,Sku销售属性相关信息
5,Sku价格信息(平台可以单独修改价格,sku后续会放入缓存,为了回显最新价格,所以单独获取)
6,展示商品的海报
7,获取skuId 对应的商品规格参数
模块规划思路:
1,service-item微服务模块封装详情页面所需数据接口;
2,service-item通过feign client调用其他微服务数据接口进行数据汇总;
3,pc端前台页面通过web-all调用service-item数据接口渲染页面;
4,service-item可以为pc端、H5、安卓与ios等前端应用提供数据接口,web-all为pc端页面渲染形式
5,service-item获取商品信息需要调用service-product服务sku信息等;
6,由于service各微服务可能会相互调用,调用方式都是通过feign client调用,所以我们把feign client api接口单独封装出来,需要时直接引用feign client api模块接口即可,即需创建service-client父模块,管理各service微服务feign client api接口。
点击service,选择New–>Module,操作如下
下一步
下一步
完成,结构如下
修改配置pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>com.atguigu.gmallgroupId>
<artifactId>serviceartifactId>
<version>1.0version>
parent>
<artifactId>service-itemartifactId>
<version>1.0version>
<packaging>jarpackaging>
<name>service-itemname>
<description>service-itemdescription>
<build>
<finalName>service-itemfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
添加配置文件bootstrap.properties
spring.application.name=service-item
spring.profiles.active=dev
spring.cloud.nacos.discovery.server-addr=192.168.200.129:8848
spring.cloud.nacos.config.server-addr=192.168.200.129:8848
spring.cloud.nacos.config.prefix=${spring.application.name}
spring.cloud.nacos.config.file-extension=yaml
spring.cloud.nacos.config.shared-configs[0].data-id=common.yaml
添加启动类
exclude = DataSourceAutoConfiguration.class 排除数据库链接****jar
表示当前项目**{service-item}** 不参与数据库查询
package com.atguigu.gmall.item;
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
@ComponentScan({"com.atguigu.gmall"})
@EnableDiscoveryClient
@EnableFeignClients(basePackages= {"com.atguigu.gmall"})
public class ServiceItemApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceItemApplication.class, args);
}
}
接口
package com.atguigu.gmall.item.service;
public interface ItemService {
/**
* 获取sku详情信息
* @param skuId
* @return
*/
Map<String, Object> getBySkuId(Long skuId);
}
实现类
@Service
public class ItemServiceImpl implements ItemService {
@Override
public Map<String, Object> getBySkuId(Long skuId) {
Map<String, Object> result = new HashMap<>();
return result;
}
}
controller
@RestController
@RequestMapping("api/item")
public class ItemApiController {
@Autowired
private ItemService itemService;
/**
* 获取sku详情信息
* @param skuId
* @return
*/
@GetMapping("{skuId}")
public Result getItem(@PathVariable Long skuId){
Map<String,Object> result = itemService.getBySkuId(skuId);
return Result.ok(result);
}
}
说明:商品详情相关信息在service-product微服务都可以获取,所以我们在service-product模块编写所需要的接口
service-product模块编写所需要的接口
ManageService
接口
/**
* 根据skuId 查询skuInfo
* @param skuId
* @return
*/
SkuInfo getSkuInfo(Long skuId);
实现类
@Override
public SkuInfo getSkuInfo(Long skuId) {
SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
// 根据skuId 查询图片列表集合
QueryWrapper<SkuImage> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("sku_id", skuId);
List<SkuImage> skuImageList = skuImageMapper.selectList(queryWrapper);
skuInfo.setSkuImageList(skuImageList);
return skuInfo;
}
package com.atguigu.gmall.product.api.ProductApiController
@RestController
@RequestMapping("api/product")
public class ProductApiController {
@Autowired
private ManageService manageService;
/**
* 根据skuId获取sku信息
* @param skuId
* @return
*/
@GetMapping("inner/getSkuInfo/{skuId}")
public SkuInfo getAttrValueList(@PathVariable("skuId") Long skuId){
SkuInfo skuInfo = manageService.getSkuInfo(skuId);
return skuInfo;
}
sku是挂在三级分类下面的,我们的分类信息分别在base_category1、base_category2、base_category3这三张表里面,目前需要通过sku表的三级分类id获取一级分类名称、二级分类名称和三级分类名称
MySQL 视图(View)是一种虚拟存在的表,同真实表一样,视图也由列和行构成,但视图并不实际存在于数据库中。行和列的数据来自于定义视图的查询中所使用的表,并且还是在使用视图时动态生成的。
特点:
数据库中只存放了视图的定义,并没有存放视图中的数据,这些数据都存放在定义视图查询所引用的真实表中。
我们可以建立一个视图****(view),把三张表关联起来,视图id就是三级分类id,这样通过三级分类id就可以查询到相应数据,效果如下:
创建视图
CREATE VIEW base_category_view AS
select
c3.id as id,
c1.id as category1_id, c1.name as category1_name,
c2.id as category2_id, c2.name as category2_name,
c3.id as category3_id, c3.name as category3_name
from base_category1 c1
inner join base_category2 c2 on c2.category1_id = c1.id
inner join base_category3 c3 on c3.category2_id = c2.id
Mapper
@Mapper
public interface BaseCategoryViewMapper extends BaseMapper<BaseCategoryView> {
}
ManageService
接口
/**
* 通过三级分类id查询分类信息
* @param category3Id
* @return
*/
BaseCategoryView getCategoryViewByCategory3Id(Long category3Id);
接口实现
@Override
public BaseCategoryView getCategoryViewByCategory3Id(Long category3Id) {
return baseCategoryViewMapper.selectById(category3Id);
}
ProductApiController
ProductApiController
/**
* 通过三级分类id查询分类信息
* @param category3Id
* @return
*/
@GetMapping("inner/getCategoryView/{category3Id}")
public BaseCategoryView getCategoryView(@PathVariable("category3Id")Long category3Id){
return manageService.getCategoryViewByCategory3Id(category3Id);
}
/**
* 获取sku价格
* @param skuId
* @return
*/
BigDecimal getSkuPrice(Long skuId);
/**
* 获取sku价格
* @param skuId
* @return
*/
@Override
public BigDecimal getSkuPrice(Long skuId) {
SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
if(null != skuInfo) {
return skuInfo.getPrice();
}
return new BigDecimal("0");
}
/**
* 获取sku最新价格
* @param skuId
* @return
*/
@GetMapping("inner/getSkuPrice/{skuId}")
public BigDecimal getSkuPrice(@PathVariable Long skuId){
return manageService.getSkuPrice(skuId);
}
思路:
1、查出该商品的spu的所有销售属性和属性值
2、标识出本商品对应的销售属性
3、点击其他销售属性值的组合,跳转到另外的sku页面
第1、2条通过此sql实现
SELECT sa.id ,sa.spu_id, sa.sale_attr_name,sa.base_sale_attr_id,
sv.id sale_attr_value_id,
sv.sale_attr_value_name,
skv.sku_id,
IF(skv.sku_id IS NULL,0,1) is_checked
FROM spu_sale_attr sa
INNER JOIN spu_sale_attr_value sv ON sa.spu_id=sv.spu_id AND sa.base_sale_attr_id=sv.base_sale_attr_id
LEFT JOIN sku_sale_attr_value skv ON skv.sale_attr_value_id= sv.id AND skv.sku_id=#{skuId}
WHERE sa.spu_id=#{spuId}
ORDER BY sv.base_sale_attr_id,sv.id
此sql列出所有该spu的销售属性和属性值,并关联某skuid如果能关联上is_check设为1,否则设为0。
在对应的实体类中【SpuSaleAttrValue】添加属性字段
@TableField(exist = false)
String isChecked;
MyBatisPlus有个不起眼的字段@TableField,一般不是必须的。但是他有一个属性exist,是表示这个字段在数据库中是否存在(是否实体字段),与JPA的@Transient是类似的。
于是乎,加个@TableField(exist = false)搞定
@TableField(exist = false):表示该属性不为数据库表字段,但又是必须使用的。
@TableField(exist = true):表示该属性为数据库表字段。
接口 :SpuSaleAttrMapper
// 根据spuId,skuId 查询销售属性集合
List<SpuSaleAttr> selectSpuSaleAttrListCheckBySku(@Param("skuId") Long skuId, @Param("spuId")Long spuId);
<select id="selectSpuSaleAttrListCheckBySku" resultMap="spuSaleAttrMap">
SELECT sa.id ,sa.spu_id, sa.sale_attr_name,sa.base_sale_attr_id,
sv.id sale_attr_value_id,
sv.sale_attr_value_name,
skv.sku_id,
IF(skv.sku_id IS NULL,0,1) is_checked
FROM spu_sale_attr sa
INNER JOIN spu_sale_attr_value sv ON sa.spu_id=sv.spu_id AND sa.base_sale_attr_id=sv.base_sale_attr_id
LEFT JOIN sku_sale_attr_value skv ON skv.sale_attr_value_id= sv.id AND skv.sku_id=#{skuId}
WHERE sa.spu_id=#{spuId}
ORDER BY sv.base_sale_attr_id,sv.id
</select>
接口
/**
* 根据spuId,skuId 查询销售属性集合
* @param skuId
* @param spuId
* @return
*/
List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId);
实现类
@Override
public List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId) {
return spuSaleAttrMapper.selectSpuSaleAttrListCheckBySku(skuId, spuId);
}
ProductApiController
/**
* 根据spuId,skuId 查询销售属性集合
* @param skuId
* @param spuId
* @return
*/
@GetMapping("inner/getSpuSaleAttrListCheckBySku/{skuId}/{spuId}")
public List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(@PathVariable("skuId") Long skuId,@PathVariable("spuId") Long spuId){
return manageService.getSpuSaleAttrListCheckBySku(skuId, spuId);
}
实现思路:
1 、从页面中获得得所有选中的销售属性进行组合比如:
“属性值1|属性值2” 用这个字符串匹配一个对照表,来获得skuId。并进行跳转,或者告知无货。
2、后台要生成一个“属性值1|属性值2:skuId”的一个json串以提供页面进行匹配。如
3、需要从后台数据库查询出该spu下的所有skuId和属性值关联关系。然后加工成如上的Json串,用该json串,跟前台匹配。
实现:
使用sql 语句来解决:
GROUP_CONCAT:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator '分隔符'] )
SkuSaleAttrValueMapper
// 根据spuId 查询map 集合数据
List<Map> selectSaleAttrValuesBySpu(Long spuId);
SkuSaleAttrValueMapper.xml
<resultMap id="spuValueIdsMap" type="java.util.Map" autoMapping="true">
resultMap>
<select id="selectSaleAttrValuesBySpu" resultMap="spuValueIdsMap">
SELECT sku_id , GROUP_CONCAT(sale_attr_value_id ORDER BY sp.base_sale_attr_id ASC SEPARATOR '|') value_ids
FROM `sku_sale_attr_value` sv
INNER JOIN `spu_sale_attr_value` sp on sp.id = sv.sale_attr_value_id
WHERE sv.spu_id=#{spuId}
GROUP BY sku_id
select>
ManageService
接口
/**
* 根据spuId 查询map 集合属性
* @param spuId
* @return
*/
Map getSkuValueIdsMap(Long spuId);
实现类
@Override
public Map getSkuValueIdsMap(Long spuId) {
Map<Object, Object> map = new HashMap<>();
// key = 125|123 ,value = 37
List<Map> mapList = skuSaleAttrValueMapper.selectSaleAttrValuesBySpu(spuId);
if (mapList != null && mapList.size() > 0) {
// 循环遍历
for (Map skuMap : mapList) {
// key = 125|123 ,value = 37
map.put(skuMap.get("value_ids"), skuMap.get("sku_id"));
}
}
return map;
}
ProductApiController
/**
* 根据spuId 查询map 集合属性
* @param spuId
* @return
*/
@GetMapping("inner/getSkuValueIdsMap/{spuId}")
public Map getSkuValueIdsMap(@PathVariable("spuId") Long spuId){
return manageService.getSkuValueIdsMap(spuId);
}
接口
/**
* 根据spuid获取商品海报
* @param spuId
* @return
*/
List<SpuPoster> findSpuPosterBySpuId(Long spuId);
实现类
@Override
public List<SpuPoster> findSpuPosterBySpuId(Long spuId) {
QueryWrapper<SpuPoster> spuInfoQueryWrapper = new QueryWrapper<>();
spuInfoQueryWrapper.eq("spu_id",spuId);
List<SpuPoster> spuPosterList = spuPosterMapper.selectList(spuInfoQueryWrapper);
return spuPosterList;
}
// 根据spuId 获取海报数据
@GetMapping("inner/findSpuPosterBySpuId/{spuId}")
public List<SpuPoster> findSpuPosterBySpuId(@PathVariable Long spuId){
return manageService.findSpuPosterBySpuId(spuId);
}
显示在商品详情规格处
ManageService
/**
* 通过skuId 集合来查询数据
* @param skuId
* @return
*/
List<BaseAttrInfo> getAttrList(Long skuId);
实现类
@Override
public List<BaseAttrInfo> getAttrList(Long skuId) {
return baseAttrInfoMapper.selectBaseAttrInfoListBySkuId(skuId);
}
BaseAttrInfoMapper 添加方法
/**
*
* @param skuId
*/
List<BaseAttrInfo> selectBaseAttrInfoListBySkuId(@Param("skuId")Long skuId);
BaseAttrInfoMapper.xml添加
<select id="selectBaseAttrInfoListBySkuId" resultMap="baseAttrInfoMap">
SELECT
bai.id,
bai.attr_name,
bai.category_id,
bai.category_level,
bav.id attr_value_id,
bav.value_name,
bav.attr_id
FROM
base_attr_info bai
INNER JOIN base_attr_value bav ON bai.id = bav.attr_id
INNER JOIN sku_attr_value sav ON sav.value_id = bav.id
WHERE
sav.sku_id = #{skuId}
select>
ProductApiController
/**
* 通过skuId 集合来查询数据
* @param skuId
* @return
*/
@GetMapping("inner/getAttrList/{skuId}")
public List<BaseAttrInfo> getAttrList(@PathVariable("skuId") Long skuId){
return manageService.getAttrList(skuId);
}
说明:目前我们在service-product里面把数据模型已经封装好了,接下封装feign client api接口,提供给service-item微服务调用汇总数据模型
搭建方式如:common父模块
修改pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<modules>
<module>service-product-clientmodule>
<module>service-item-clientmodule>
modules>
<parent>
<groupId>com.atguigu.gmallgroupId>
<artifactId>gmall-parentartifactId>
<version>1.0version>
parent>
<artifactId>service-clientartifactId>
<packaging>pompackaging>
<version>1.0version>
<dependencies>
<dependency>
<groupId>com.atguigu.gmallgroupId>
<artifactId>common-utilartifactId>
<version>1.0version>
dependency>
<dependency>
<groupId>com.atguigu.gmallgroupId>
<artifactId>modelartifactId>
<version>1.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
<scope>provided scope>
dependency>
dependencies>
project>
在service-client 模块下创建
修改pom.xml加粗样式
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-client</artifactId>
<version>1.0</version>
</parent>
<artifactId>service-product-client</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>service-product-client</name>
<description>service-product-client</description>
</project>
package com.atguigu.gmall.product.client;
@FeignClient(value ="service-product", fallback = ProductDegradeFeignClient.class)
public interface ProductFeignClient {
/**
* 根据skuId获取sku信息
*
* @param skuId
* @return
*/
@GetMapping("/api/product/inner/getSkuInfo/{skuId}")
SkuInfo getSkuInfo(@PathVariable("skuId") Long skuId);
/**
* 通过三级分类id查询分类信息
* @param category3Id
* @return
*/
@GetMapping("/api/product/inner/getCategoryView/{category3Id}")
BaseCategoryView getCategoryView(@PathVariable("category3Id")Long category3Id);
/**
* 获取sku最新价格
*
* @param skuId
* @return
*/
@GetMapping("/api/product/inner/getSkuPrice/{skuId}")
BigDecimal getSkuPrice(@PathVariable(value = "skuId") Long skuId);
/**
* 根据spuId,skuId 查询销售属性集合
*
* @param skuId
* @param spuId
* @return
*/
@GetMapping("/api/product/inner/getSpuSaleAttrListCheckBySku/{skuId}/{spuId}")
List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(@PathVariable("skuId") Long skuId, @PathVariable("spuId") Long spuId);
/**
* 根据spuId 查询map 集合属性
* @param spuId
* @return
*/
@GetMapping("/api/product/inner/getSkuValueIdsMap/{spuId}")
Map getSkuValueIdsMap(@PathVariable("spuId") Long spuId);
// 根据spuId 获取海报数据
@GetMapping("/api/product/inner/findSpuPosterBySpuId/{spuId}")
List<SpuPoster> getSpuPosterBySpuId(@PathVariable Long spuId);
/**
* 通过skuId 集合来查询数据
* @param skuId
* @return
*/
@GetMapping("/api/product/inner/getAttrList/{skuId}")
List<BaseAttrInfo> getAttrList(@PathVariable("skuId") Long skuId);
}
@Component
public class ProductDegradeFeignClient implements ProductFeignClient {
@Override
public SkuInfo getSkuInfo(Long skuId) {
return null;
}
@Override
public BaseCategoryView getCategoryView(Long category3Id) {
return null;
}
@Override
public BigDecimal getSkuPrice(Long skuId) {
return null;
}
@Override
public List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId) {
return null;
}
@Override
public Map getSkuValueIdsMap(Long spuId) {
return null;
}
@Override
public List<SpuPoster> getSpuPosterBySpuId(Long spuId) {
return null;
}
@Override
public List<BaseAttrInfo> getAttrList(Long skuId) {
return null;
}
}
说明:接下来service-item引用service-product-client模块,就可以调用相应接口
在service-item pom.xml引用依赖:
<dependency>
<groupId>com.atguigu.gmallgroupId>
<artifactId>service-product-clientartifactId>
<version>1.0version>
dependency>
@Service
public class ItemServiceImpl implements ItemService {
// 远程调用service-product-client
@Autowired
private ProductFeignClient productFeignClient;
@Override
public Map<String, Object> getItemBySkuId(Long skuId) {
// 声明对象
Map<String, Object> result = new HashMap<>();
// 获取到的数据是skuInfo + skuImageList
SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
// 判断skuInfo 不为空
if (skuInfo!=null){
// 获取分类数据
BaseCategoryView categoryView = productFeignClient.getCategoryView(skuInfo.getCategory3Id());
result.put("categoryView",categoryView);
// 获取销售属性+销售属性值
List<SpuSaleAttr> spuSaleAttrListCheckBySku = productFeignClient.getSpuSaleAttrListCheckBySku(skuId, skuInfo.getSpuId());
result.put("spuSaleAttrList",spuSaleAttrListCheckBySku);
// 查询销售属性值Id 与skuId 组合的map
Map skuValueIdsMap = productFeignClient.getSkuValueIdsMap(skuInfo.getSpuId());
// 将这个map 转换为页面需要的Json 对象
String valueJson = JSON.toJSONString(skuValueIdsMap);
result.put("valuesSkuJson",valueJson);
}
// 获取价格
BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
// map 中 key 对应的谁? Thymeleaf 获取数据的时候 ${skuInfo.skuName}
result.put("skuInfo",skuInfo);
result.put("price",skuPrice);
// 返回map 集合 Thymeleaf 渲染:能用map 存储数据!
// spu海报数据
List<SpuPoster> spuPosterList = productFeignClient.findSpuPosterBySpuId(skuInfo.getSpuId());
result.put("spuPosterList", spuPosterList);
List<BaseAttrInfo> attrList = productFeignClient.getAttrList(skuId);
// 使用拉姆达表示
List<Map<String, String>> skuAttrList = attrList.stream().map((baseAttrInfo) -> {
Map<String, String> attrMap = new HashMap<>();
attrMap.put("attrName", baseAttrInfo.getAttrName());
attrMap.put("attrValue", baseAttrInfo.getAttrValueList().get(0).getValueName());
return attrMap;
}).collect(Collectors.toList());
result.put("skuAttrList", skuAttrList);
return result;
}
}
在service-client 目录下创建。
搭建方式同service-product-client
接口类
package com.atguigu.gmall.item.client
@FeignClient(value = "service-item", fallback = ItemDegradeFeignClient.class)
public interface ItemFeignClient {
/**
* @param skuId
* @return
*/
@GetMapping("/api/item/{skuId}")
Result getItem(@PathVariable("skuId") Long skuId);
}
@Component
public class ItemDegradeFeignClient implements ItemFeignClient {
@Override
public Result getItem(Long skuId) {
return Result.fail();
}
}
搭建方式如service-util
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>commonartifactId>
<groupId>com.atguigu.gmallgroupId>
<version>1.0version>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>web-utilartifactId>
<dependencies>
<dependency>
<groupId>com.atguigu.gmallgroupId>
<artifactId>common-utilartifactId>
<version>1.0version>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<scope>provided scope>
dependency>
dependencies>
project>
导入工具类:
构建方式如:common父模块
修改配置pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modules>
<module>web-allmodule>
modules>
<parent>
<groupId>com.atguigu.gmallgroupId>
<artifactId>gmall-parentartifactId>
<version>1.0version>
parent>
<artifactId>webartifactId>
<packaging>pompackaging>
<version>1.0version>
<dependencies>
<dependency>
<groupId>com.atguigu.gmallgroupId>
<artifactId>web-utilartifactId>
<version>1.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
dependencies>
project>
搭建方式在web模块下创建
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>com.atguigu.gmallgroupId>
<artifactId>webartifactId>
<version>1.0version>
parent>
<artifactId>web-allartifactId>
<version>1.0version>
<packaging>jarpackaging>
<name>web-all name>
<description>web-all description>
<dependencies>
<dependency>
<groupId>com.atguigu.gmallgroupId>
<artifactId>service-item-clientartifactId>
<version>1.0version>
dependency>
dependencies>
<build>
<finalName>web-allfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
bootstrap.properties
spring.application.name=web-all
spring.profiles.active=dev
spring.cloud.nacos.discovery.server-addr=192.168.200.129:8848
spring.cloud.nacos.config.server-addr=192.168.200.129:8848
spring.cloud.nacos.config.prefix=${spring.application.name}
spring.cloud.nacos.config.file-extension=yaml
启动类;
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
@ComponentScan({"com.atguigu.gmall"})
@EnableDiscoveryClient
@EnableFeignClients(basePackages= {"com.atguigu.gmall"})
public class WebAllApplication {
public static void main(String[] args) {
SpringApplication.run(WebAllApplication.class, args);
}
}
1,由于我们的微服务接口都是通过网关暴露服务,所以需要配置网关
server-gateway网关添加配置:
routes:
- id: service-product
uri: lb://service-product
predicates:
- Path=/*/product/** # 路径匹配
- id: service-item
uri: lb://service-item
predicates:
- Path=/*/item/**
#==================web前端==========================
- id: web-item
uri: lb://web-all
predicates:
- Host=item.gmall.com
在web-all 工 将这两个文件夹放入到resouces 文件夹中。
导入之后,可能发送异常警告
解决方案:
Package com.atguigu.gmall.all.controller
@Controller
public class ItemController {
@Autowired
private ItemFeignClient itemFeignClient;
/**
* sku详情页面
* @param skuId
* @param model
* @return
*/
@RequestMapping("{skuId}.html")
public String getItem(@PathVariable Long skuId, Model model){
// 通过skuId 查询skuInfo
Result<Map> result = itemFeignClient.getItem(skuId);
model.addAllAttributes(result.getData());
return "item/index";
}
}