Commit 4ee4435a55490e9e4ad0d62fbe54d1e7f7ac2870
1 parent
15f913dc
feat(静态页面生成): 实现产品列表静态页面生成功能
- 新增静态页面配置和生成逻辑 - 添加 FreeMarker 模板支持 - 实现产品数据动态加载和渲染 - 优化产品价格显示逻辑 - 新增静态资源路径配置
Showing
10 changed files
with
131 additions
and
12 deletions
Too many changes to show.
To preserve performance only 10 of 11 files are displayed.
pom.xml
@@ -81,6 +81,14 @@ | @@ -81,6 +81,14 @@ | ||
81 | <artifactId>mybatis-plus-boot-starter</artifactId> | 81 | <artifactId>mybatis-plus-boot-starter</artifactId> |
82 | <version>${baomidou.version}</version> | 82 | <version>${baomidou.version}</version> |
83 | </dependency> | 83 | </dependency> |
84 | + | ||
85 | + <dependency> | ||
86 | + <groupId>org.springframework.boot</groupId> | ||
87 | + <artifactId>spring-boot-starter-freemarker</artifactId> | ||
88 | + <version>3.3.5</version> | ||
89 | + </dependency> | ||
90 | + | ||
91 | + | ||
84 | <dependency> | 92 | <dependency> |
85 | <groupId>cn.hutool</groupId> | 93 | <groupId>cn.hutool</groupId> |
86 | <artifactId>hutool-crypto</artifactId> | 94 | <artifactId>hutool-crypto</artifactId> |
shop/pom.xml
@@ -38,6 +38,11 @@ | @@ -38,6 +38,11 @@ | ||
38 | </dependency> | 38 | </dependency> |
39 | <dependency> | 39 | <dependency> |
40 | <groupId>org.springframework.boot</groupId> | 40 | <groupId>org.springframework.boot</groupId> |
41 | + <artifactId>spring-boot-starter-freemarker</artifactId> | ||
42 | + <version>3.3.5</version> | ||
43 | + </dependency> | ||
44 | + <dependency> | ||
45 | + <groupId>org.springframework.boot</groupId> | ||
41 | <artifactId>spring-boot-starter-aop</artifactId> | 46 | <artifactId>spring-boot-starter-aop</artifactId> |
42 | </dependency> | 47 | </dependency> |
43 | <dependency> | 48 | <dependency> |
shop/src/main/java/com/canrd/shop/config/StaticHtmlConfig.java
0 → 100644
1 | +package com.canrd.shop.config; | ||
2 | + | ||
3 | +import lombok.Data; | ||
4 | +import org.springframework.beans.factory.annotation.Value; | ||
5 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
6 | +import org.springframework.stereotype.Component; | ||
7 | + | ||
8 | +import java.util.Map; | ||
9 | + | ||
10 | +@Component | ||
11 | +@Data | ||
12 | +@ConfigurationProperties(prefix = "static-html.product-list") | ||
13 | +public class StaticHtmlConfig { | ||
14 | + | ||
15 | + private String url; | ||
16 | + | ||
17 | +} |
shop/src/main/java/com/canrd/shop/controller/ProductController.java
@@ -2,26 +2,29 @@ package com.canrd.shop.controller; | @@ -2,26 +2,29 @@ package com.canrd.shop.controller; | ||
2 | 2 | ||
3 | import com.canrd.shop.common.constant.ServerResult; | 3 | import com.canrd.shop.common.constant.ServerResult; |
4 | import com.canrd.shop.common.jsr303.OperateGroup; | 4 | import com.canrd.shop.common.jsr303.OperateGroup; |
5 | +import com.canrd.shop.config.StaticHtmlConfig; | ||
6 | +import com.canrd.shop.module.dto.ProductDO; | ||
5 | import com.canrd.shop.module.vo.ProductCategoryQueryVO; | 7 | import com.canrd.shop.module.vo.ProductCategoryQueryVO; |
6 | import com.canrd.shop.module.vo.ProductQueryVO; | 8 | import com.canrd.shop.module.vo.ProductQueryVO; |
7 | import com.canrd.shop.module.vo.ProductVO; | 9 | import com.canrd.shop.module.vo.ProductVO; |
8 | import com.canrd.shop.service.ProductCategoryService; | 10 | import com.canrd.shop.service.ProductCategoryService; |
9 | import com.canrd.shop.service.ProductService; | 11 | import com.canrd.shop.service.ProductService; |
10 | -import org.apache.commons.collections.Transformer; | ||
11 | -import org.apache.commons.collections.functors.ChainedTransformer; | ||
12 | -import org.apache.commons.collections.functors.ConstantTransformer; | ||
13 | -import org.apache.commons.collections.functors.InvokerTransformer; | ||
14 | -import org.apache.commons.collections.keyvalue.TiedMapEntry; | ||
15 | -import org.apache.commons.collections.map.LazyMap; | 12 | +import freemarker.template.Configuration; |
13 | +import freemarker.template.Template; | ||
14 | +import freemarker.template.TemplateException; | ||
15 | +import org.apache.commons.lang3.StringUtils; | ||
16 | import org.springframework.beans.factory.annotation.Autowired; | 16 | import org.springframework.beans.factory.annotation.Autowired; |
17 | +import org.springframework.beans.factory.annotation.Value; | ||
18 | +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; | ||
17 | import org.springframework.validation.annotation.Validated; | 19 | import org.springframework.validation.annotation.Validated; |
18 | import org.springframework.web.bind.annotation.*; | 20 | import org.springframework.web.bind.annotation.*; |
19 | 21 | ||
20 | import javax.annotation.Resource; | 22 | import javax.annotation.Resource; |
21 | import java.io.*; | 23 | import java.io.*; |
22 | import java.lang.reflect.Field; | 24 | import java.lang.reflect.Field; |
23 | -import java.util.HashMap; | ||
24 | -import java.util.Map; | 25 | +import java.net.URL; |
26 | +import java.util.*; | ||
27 | +import java.util.stream.Stream; | ||
25 | 28 | ||
26 | /** | 29 | /** |
27 | * (Product)表控制层 | 30 | * (Product)表控制层 |
@@ -32,6 +35,13 @@ import java.util.Map; | @@ -32,6 +35,13 @@ import java.util.Map; | ||
32 | @RestController | 35 | @RestController |
33 | @RequestMapping("/shop/product") | 36 | @RequestMapping("/shop/product") |
34 | public class ProductController { | 37 | public class ProductController { |
38 | + @Autowired | ||
39 | + private Configuration freeMarkerConfig; | ||
40 | + @Value("${spring.profiles.active}") | ||
41 | + private String activeProfile; | ||
42 | + | ||
43 | + @Autowired | ||
44 | + private StaticHtmlConfig staticHtmlConfig; | ||
35 | /** | 45 | /** |
36 | * 服务对象 | 46 | * 服务对象 |
37 | */ | 47 | */ |
@@ -69,6 +79,47 @@ public class ProductController { | @@ -69,6 +79,47 @@ public class ProductController { | ||
69 | } | 79 | } |
70 | 80 | ||
71 | /** | 81 | /** |
82 | + * 分页查询 | ||
83 | + * | ||
84 | + * @param productQueryVO 查询条件 | ||
85 | + * @return 查询结果 | ||
86 | + */ | ||
87 | + @GetMapping("/generateList") | ||
88 | + public ServerResult generateList(@Validated({OperateGroup.List.class}) ProductQueryVO productQueryVO) throws IOException, TemplateException { | ||
89 | + String path = staticHtmlConfig.getUrl(); | ||
90 | + String fileName = Optional.ofNullable(productQueryVO.getRootProductCategoryId()).orElse("-")+"_" | ||
91 | + +Optional.ofNullable(productQueryVO.getProductCategoryId()).orElse("-")+"_" | ||
92 | + +Optional.ofNullable(productQueryVO.getProductFunctionId()).orElse("-")+"_" | ||
93 | + +Optional.ofNullable(productQueryVO.getKeyword()).orElse("-").trim(); | ||
94 | + Map res = (Map) productService.listBySimilar(productQueryVO).getData(); | ||
95 | + List<ProductDO> itemList = (List<ProductDO>) res.get("records"); | ||
96 | + | ||
97 | + // 将数据模型放入 map | ||
98 | + Map<String, Object> dataModel = new HashMap<>(); | ||
99 | + dataModel.put("items", itemList); | ||
100 | + | ||
101 | + // 获取 FreeMarker 模板 | ||
102 | + Template template = freeMarkerConfig.getTemplate("canrud.ftl"); | ||
103 | + | ||
104 | + // 渲染模板并保存到文件 | ||
105 | + String renderedTemplate = FreeMarkerTemplateUtils.processTemplateIntoString(template, dataModel); | ||
106 | + | ||
107 | + //将renderedTemplate写入到path目录 | ||
108 | + String outputDir = path; | ||
109 | + | ||
110 | + // 指定文件路径 | ||
111 | + File outputFile = new File(outputDir, fileName+".html"); | ||
112 | + | ||
113 | + // 将渲染后的内容写入文件 | ||
114 | + try (FileWriter writer = new FileWriter(outputFile)) { | ||
115 | + writer.write(renderedTemplate); | ||
116 | + } | ||
117 | + | ||
118 | + System.out.println("文件已成功保存到 " + outputFile.getAbsolutePath()); | ||
119 | + return null; | ||
120 | + } | ||
121 | + | ||
122 | + /** | ||
72 | * 通过主键查询单条数据 | 123 | * 通过主键查询单条数据 |
73 | * | 124 | * |
74 | * @param productQueryVO 查询条件 | 125 | * @param productQueryVO 查询条件 |
shop/src/main/java/com/canrd/shop/module/dto/ProductDO.java
@@ -48,6 +48,7 @@ public class ProductDO implements Serializable { | @@ -48,6 +48,7 @@ public class ProductDO implements Serializable { | ||
48 | 48 | ||
49 | private Double marketprice; | 49 | private Double marketprice; |
50 | 50 | ||
51 | + | ||
51 | private String metadescription; | 52 | private String metadescription; |
52 | 53 | ||
53 | private String metakeywords; | 54 | private String metakeywords; |
@@ -130,6 +131,8 @@ public class ProductDO implements Serializable { | @@ -130,6 +131,8 @@ public class ProductDO implements Serializable { | ||
130 | @TableField(value = "productType_id") | 131 | @TableField(value = "productType_id") |
131 | private String productTypeId; | 132 | private String productTypeId; |
132 | 133 | ||
134 | + private String imageFileKey; | ||
135 | + | ||
133 | @TableField(exist = false) | 136 | @TableField(exist = false) |
134 | private Integer similar; | 137 | private Integer similar; |
135 | @TableField(exist = false) | 138 | @TableField(exist = false) |
shop/src/main/java/com/canrd/shop/service/impl/ProductServiceImpl.java
@@ -2,6 +2,7 @@ package com.canrd.shop.service.impl; | @@ -2,6 +2,7 @@ package com.canrd.shop.service.impl; | ||
2 | 2 | ||
3 | import cn.hutool.core.bean.BeanUtil; | 3 | import cn.hutool.core.bean.BeanUtil; |
4 | import cn.hutool.core.collection.CollUtil; | 4 | import cn.hutool.core.collection.CollUtil; |
5 | +import com.alibaba.fastjson2.JSON; | ||
5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 6 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
6 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | 7 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
7 | import com.baomidou.mybatisplus.core.metadata.IPage; | 8 | import com.baomidou.mybatisplus.core.metadata.IPage; |
@@ -180,15 +181,24 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im | @@ -180,15 +181,24 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im | ||
180 | } | 181 | } |
181 | Set<String> productIds = null; | 182 | Set<String> productIds = null; |
182 | Map<String,List<TicketTypeDO>> pId2ttDOsMap = null; | 183 | Map<String,List<TicketTypeDO>> pId2ttDOsMap = null; |
184 | + Map<String,BigDecimal> pId2ttMinPriceMap = null; | ||
183 | boolean needLikeMatch = false; | 185 | boolean needLikeMatch = false; |
184 | if(StringUtils.isNotBlank(productQueryVO.getKeyword())){ | 186 | if(StringUtils.isNotBlank(productQueryVO.getKeyword())){ |
185 | List<TicketTypeDO> tickeyTypeDOList = ticketTypeService.lambdaQuery().like(TicketTypeDO::getRank, productQueryVO.getKeyword()).list(); | 187 | List<TicketTypeDO> tickeyTypeDOList = ticketTypeService.lambdaQuery().like(TicketTypeDO::getRank, productQueryVO.getKeyword()).list(); |
186 | productIds = tickeyTypeDOList.stream().map(TicketTypeDO::getProductId).collect(Collectors.toSet()); | 188 | productIds = tickeyTypeDOList.stream().map(TicketTypeDO::getProductId).collect(Collectors.toSet()); |
187 | needLikeMatch = true; | 189 | needLikeMatch = true; |
188 | pId2ttDOsMap = new HashMap<>(); | 190 | pId2ttDOsMap = new HashMap<>(); |
191 | + pId2ttMinPriceMap = new HashMap<>(); | ||
189 | for (TicketTypeDO ticketTypeDO : tickeyTypeDOList) { | 192 | for (TicketTypeDO ticketTypeDO : tickeyTypeDOList) { |
190 | pId2ttDOsMap.computeIfAbsent(ticketTypeDO.getProductId(), k -> new ArrayList<>()); | 193 | pId2ttDOsMap.computeIfAbsent(ticketTypeDO.getProductId(), k -> new ArrayList<>()); |
191 | pId2ttDOsMap.get(ticketTypeDO.getProductId()).add(ticketTypeDO); | 194 | pId2ttDOsMap.get(ticketTypeDO.getProductId()).add(ticketTypeDO); |
195 | + if (Objects.isNull(pId2ttMinPriceMap.get(ticketTypeDO.getProductId()))){ | ||
196 | + pId2ttMinPriceMap.put(ticketTypeDO.getProductId(), ticketTypeDO.getPrice()); | ||
197 | + }else { | ||
198 | + if (pId2ttMinPriceMap.get(ticketTypeDO.getProductId()).compareTo(ticketTypeDO.getPrice())>0){ | ||
199 | + pId2ttMinPriceMap.put(ticketTypeDO.getProductId(), ticketTypeDO.getPrice()); | ||
200 | + } | ||
201 | + } | ||
192 | } | 202 | } |
193 | Set<String> finalProductIds = productIds; | 203 | Set<String> finalProductIds = productIds; |
194 | queryWapper.and(subQueryWapper -> { | 204 | queryWapper.and(subQueryWapper -> { |
@@ -206,7 +216,13 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im | @@ -206,7 +216,13 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im | ||
206 | } | 216 | } |
207 | }); | 217 | }); |
208 | List<ProductDO> similarProductList = Lists.newArrayList(); | 218 | List<ProductDO> similarProductList = Lists.newArrayList(); |
219 | + Boolean productPriceShow = switchControlService.getEnabledByName(SwitchControlConstants.PRODUCT_PRICE_SHOW); | ||
209 | for(ProductDO product:productDOS){ | 220 | for(ProductDO product:productDOS){ |
221 | + if (productPriceShow){ | ||
222 | + if (Objects.nonNull(pId2ttMinPriceMap.get(product.getId()))){ | ||
223 | + product.setPrice(pId2ttMinPriceMap.get(product.getId())); | ||
224 | + } | ||
225 | + } | ||
210 | if(accurateProductIdSet.contains(product.getId())){ | 226 | if(accurateProductIdSet.contains(product.getId())){ |
211 | continue; | 227 | continue; |
212 | } | 228 | } |
@@ -235,7 +251,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im | @@ -235,7 +251,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im | ||
235 | List<ProductDO> allProductList = Lists.newArrayList(); | 251 | List<ProductDO> allProductList = Lists.newArrayList(); |
236 | allProductList.addAll(accurateProducts); | 252 | allProductList.addAll(accurateProducts); |
237 | allProductList.addAll(similarProductList); | 253 | allProductList.addAll(similarProductList); |
238 | - | 254 | + allProductList.forEach(productDO -> { |
255 | + //将productDO的productimageliststore解析为map | ||
256 | + List<Map> maps = JSON.parseArray(productDO.getProductimageliststore(), Map.class); | ||
257 | + Map map = maps.get(0); | ||
258 | + productDO.setImageFileKey(map.get("fileKey").toString()); | ||
259 | + }); | ||
239 | return pager(productQueryVO,allProductList); | 260 | return pager(productQueryVO,allProductList); |
240 | } | 261 | } |
241 | 262 |
shop/src/main/java/com/canrd/shop/service/impl/SwitchControlServiceImpl.java
@@ -4,9 +4,9 @@ import com.canrd.shop.module.dto.SwitchControl; | @@ -4,9 +4,9 @@ import com.canrd.shop.module.dto.SwitchControl; | ||
4 | import com.canrd.shop.mapper.SwitchControlMapper; | 4 | import com.canrd.shop.mapper.SwitchControlMapper; |
5 | import com.canrd.shop.service.ISwitchControlService; | 5 | import com.canrd.shop.service.ISwitchControlService; |
6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
7 | -import org.apache.commons.collections.CollectionUtils; | ||
8 | import org.apache.commons.lang3.BooleanUtils; | 7 | import org.apache.commons.lang3.BooleanUtils; |
9 | import org.springframework.stereotype.Service; | 8 | import org.springframework.stereotype.Service; |
9 | +import org.springframework.util.CollectionUtils; | ||
10 | 10 | ||
11 | import java.util.List; | 11 | import java.util.List; |
12 | 12 |
shop/src/main/resources/application-prod.yml
@@ -65,3 +65,7 @@ spring: | @@ -65,3 +65,7 @@ spring: | ||
65 | 65 | ||
66 | logging: | 66 | logging: |
67 | config: classpath:log4j2-prod.xml | 67 | config: classpath:log4j2-prod.xml |
68 | + | ||
69 | +static-html: | ||
70 | + product-list: | ||
71 | + url: /etc/nginx/canrud/products_html | ||
68 | \ No newline at end of file | 72 | \ No newline at end of file |
shop/src/main/resources/application-test.yml
@@ -64,4 +64,9 @@ spring: | @@ -64,4 +64,9 @@ spring: | ||
64 | 64 | ||
65 | 65 | ||
66 | logging: | 66 | logging: |
67 | - config: classpath:log4j2-dev.xml | ||
68 | \ No newline at end of file | 67 | \ No newline at end of file |
68 | + config: classpath:log4j2-dev.xml | ||
69 | + | ||
70 | + | ||
71 | +static-html: | ||
72 | + product-list: | ||
73 | + url: E:\productList | ||
69 | \ No newline at end of file | 74 | \ No newline at end of file |
shop/src/main/resources/application.yml
@@ -3,8 +3,13 @@ server: | @@ -3,8 +3,13 @@ server: | ||
3 | 3 | ||
4 | spring: | 4 | spring: |
5 | profiles: | 5 | profiles: |
6 | - active: prod | 6 | + active: test |
7 | mvc: | 7 | mvc: |
8 | throw-exception-if-no-handler-found: true | 8 | throw-exception-if-no-handler-found: true |
9 | resources: | 9 | resources: |
10 | add-mappings: false | 10 | add-mappings: false |
11 | +static-html: | ||
12 | + product-list: | ||
13 | + urls: | ||
14 | + test: E:\productList | ||
15 | + prod: /etc/nginx/canrud/products_html | ||
11 | \ No newline at end of file | 16 | \ No newline at end of file |