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 | 81 | <artifactId>mybatis-plus-boot-starter</artifactId> |
82 | 82 | <version>${baomidou.version}</version> |
83 | 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 | 92 | <dependency> |
85 | 93 | <groupId>cn.hutool</groupId> |
86 | 94 | <artifactId>hutool-crypto</artifactId> | ... | ... |
shop/pom.xml
... | ... | @@ -38,6 +38,11 @@ |
38 | 38 | </dependency> |
39 | 39 | <dependency> |
40 | 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 | 46 | <artifactId>spring-boot-starter-aop</artifactId> |
42 | 47 | </dependency> |
43 | 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 | 2 | |
3 | 3 | import com.canrd.shop.common.constant.ServerResult; |
4 | 4 | import com.canrd.shop.common.jsr303.OperateGroup; |
5 | +import com.canrd.shop.config.StaticHtmlConfig; | |
6 | +import com.canrd.shop.module.dto.ProductDO; | |
5 | 7 | import com.canrd.shop.module.vo.ProductCategoryQueryVO; |
6 | 8 | import com.canrd.shop.module.vo.ProductQueryVO; |
7 | 9 | import com.canrd.shop.module.vo.ProductVO; |
8 | 10 | import com.canrd.shop.service.ProductCategoryService; |
9 | 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 | 16 | import org.springframework.beans.factory.annotation.Autowired; |
17 | +import org.springframework.beans.factory.annotation.Value; | |
18 | +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; | |
17 | 19 | import org.springframework.validation.annotation.Validated; |
18 | 20 | import org.springframework.web.bind.annotation.*; |
19 | 21 | |
20 | 22 | import javax.annotation.Resource; |
21 | 23 | import java.io.*; |
22 | 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 | 30 | * (Product)表控制层 |
... | ... | @@ -32,6 +35,13 @@ import java.util.Map; |
32 | 35 | @RestController |
33 | 36 | @RequestMapping("/shop/product") |
34 | 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 | 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 | 125 | * @param productQueryVO 查询条件 | ... | ... |
shop/src/main/java/com/canrd/shop/module/dto/ProductDO.java
... | ... | @@ -48,6 +48,7 @@ public class ProductDO implements Serializable { |
48 | 48 | |
49 | 49 | private Double marketprice; |
50 | 50 | |
51 | + | |
51 | 52 | private String metadescription; |
52 | 53 | |
53 | 54 | private String metakeywords; |
... | ... | @@ -130,6 +131,8 @@ public class ProductDO implements Serializable { |
130 | 131 | @TableField(value = "productType_id") |
131 | 132 | private String productTypeId; |
132 | 133 | |
134 | + private String imageFileKey; | |
135 | + | |
133 | 136 | @TableField(exist = false) |
134 | 137 | private Integer similar; |
135 | 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 | 2 | |
3 | 3 | import cn.hutool.core.bean.BeanUtil; |
4 | 4 | import cn.hutool.core.collection.CollUtil; |
5 | +import com.alibaba.fastjson2.JSON; | |
5 | 6 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
6 | 7 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
7 | 8 | import com.baomidou.mybatisplus.core.metadata.IPage; |
... | ... | @@ -180,15 +181,24 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im |
180 | 181 | } |
181 | 182 | Set<String> productIds = null; |
182 | 183 | Map<String,List<TicketTypeDO>> pId2ttDOsMap = null; |
184 | + Map<String,BigDecimal> pId2ttMinPriceMap = null; | |
183 | 185 | boolean needLikeMatch = false; |
184 | 186 | if(StringUtils.isNotBlank(productQueryVO.getKeyword())){ |
185 | 187 | List<TicketTypeDO> tickeyTypeDOList = ticketTypeService.lambdaQuery().like(TicketTypeDO::getRank, productQueryVO.getKeyword()).list(); |
186 | 188 | productIds = tickeyTypeDOList.stream().map(TicketTypeDO::getProductId).collect(Collectors.toSet()); |
187 | 189 | needLikeMatch = true; |
188 | 190 | pId2ttDOsMap = new HashMap<>(); |
191 | + pId2ttMinPriceMap = new HashMap<>(); | |
189 | 192 | for (TicketTypeDO ticketTypeDO : tickeyTypeDOList) { |
190 | 193 | pId2ttDOsMap.computeIfAbsent(ticketTypeDO.getProductId(), k -> new ArrayList<>()); |
191 | 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 | 203 | Set<String> finalProductIds = productIds; |
194 | 204 | queryWapper.and(subQueryWapper -> { |
... | ... | @@ -206,7 +216,13 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im |
206 | 216 | } |
207 | 217 | }); |
208 | 218 | List<ProductDO> similarProductList = Lists.newArrayList(); |
219 | + Boolean productPriceShow = switchControlService.getEnabledByName(SwitchControlConstants.PRODUCT_PRICE_SHOW); | |
209 | 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 | 226 | if(accurateProductIdSet.contains(product.getId())){ |
211 | 227 | continue; |
212 | 228 | } |
... | ... | @@ -235,7 +251,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im |
235 | 251 | List<ProductDO> allProductList = Lists.newArrayList(); |
236 | 252 | allProductList.addAll(accurateProducts); |
237 | 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 | 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 | 4 | import com.canrd.shop.mapper.SwitchControlMapper; |
5 | 5 | import com.canrd.shop.service.ISwitchControlService; |
6 | 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
7 | -import org.apache.commons.collections.CollectionUtils; | |
8 | 7 | import org.apache.commons.lang3.BooleanUtils; |
9 | 8 | import org.springframework.stereotype.Service; |
9 | +import org.springframework.util.CollectionUtils; | |
10 | 10 | |
11 | 11 | import java.util.List; |
12 | 12 | ... | ... |
shop/src/main/resources/application-prod.yml
shop/src/main/resources/application-test.yml
shop/src/main/resources/application.yml
... | ... | @@ -3,8 +3,13 @@ server: |
3 | 3 | |
4 | 4 | spring: |
5 | 5 | profiles: |
6 | - active: prod | |
6 | + active: test | |
7 | 7 | mvc: |
8 | 8 | throw-exception-if-no-handler-found: true |
9 | 9 | resources: |
10 | 10 | add-mappings: false |
11 | +static-html: | |
12 | + product-list: | |
13 | + urls: | |
14 | + test: E:\productList | |
15 | + prod: /etc/nginx/canrud/products_html | |
11 | 16 | \ No newline at end of file | ... | ... |