①. thymeleaf简介
1>. thymeleaf简介
1.什么是thymeleaf
- Thymeleaf是一个适用于Web和独立环境的现代服务器端Java模板引擎。SpringBoot 官网推荐使用的模板引擎是thymeleaf
2. thymeleaf PK Vue.js
vue.js 是前端渲染,异步请求(页面先打开,再看到数据),不会被搜索引擎抓取[管理后台] thymeleaf 后端渲染,比jsp还强大,支持搜索
3. thymeleaf快速入门
①.导包
<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>3.0.11.RELEASE</version> </dependency>
②. 在resource下创建一个test.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <span th:text="${name}"></span> </body> </html>
③. 创建测试类,编写代码
package com.itcast.demo; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; import org.thymeleaf.templatemode.TemplateMode; import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; import java.io.File; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; public class Test { public static void main(String[] args) { // 1.上下文 Context context = new Context(); //创建数据模型 Map<String, Object> dataModel =new HashMap(); dataModel.put("name","青橙电商系统"); context.setVariables(dataModel); // 2.准备文件 File dest = new File("d:/test_out.html"); // 3.生成页面 try { PrintWriter writer = new PrintWriter(dest, "UTF-8"); ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();//模板解析器 resolver.setTemplateMode(TemplateMode.HTML);//模板模型 resolver.setSuffix(".html");//后缀 TemplateEngine engine = new TemplateEngine();//创建模板引擎 engine.setTemplateResolver(resolver);//设置模板解析器 engine.process("test", context, writer);//执行模板引擎 } catch (Exception e) { e.printStackTrace(); } } }
4. thymeleaf标签实战
①. thymeleaf标签
②. 实战
②. 首页广告轮播图渲染
2>. 首页广告轮播图渲染
1.需求分析
- 使用Thymeleaf实现首页广告轮播图的渲染
2.表结构分析
3. 搭建网站前台工程(thymeleaf整合springBoot)
- ①. 新建qingcheng_web_portal工程,此工程为网站前台工程,pom.xml参照 qingcheng_web_manager工程,另外再添加thymeleaf-spring5依赖
<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.11.RELEASE</version> </dependency>
- ②. qingcheng_web_portal工程新建web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 解决post乱码 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext*.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>/index.do</welcome-file> </welcome-file-list> </web-app>
- ③. resources下新建配置文件applicationContext- thymeleaf.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--spring整合的资源模板解析器--> <bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"> <!--模板前缀 目录--> <property name="prefix" value="/WEB-INF/templates/"/> <!--模板后缀 扩展名--> <property name="suffix" value=".html"/> <!--字符集--> <property name="characterEncoding" value="UTF-8"/> <!--模式 html5--> <property name="templateMode" value="HTML5"/> </bean> <!--模板引擎--> <bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine"> <property name="templateResolver" ref="templateResolver"/> </bean> <!--模板视图解析器--> <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine"/> <property name="characterEncoding" value="UTF-8"/> </bean> </beans>
- ④. webapp/WEB-INF下创建templates文件夹用于存放模板文件
4. 具体代码实现
- ①. service 和 controller代码实现
@Controller public class IndexController { @Reference private AdService adService; @Reference private CategoryService categoryService; @RequestMapping("/index") public String index(Model model){ /*1.轮播图*/ List<Ad> lbList = adService.findByPosition("index_lb"); model.addAttribute("lbt",lbList); /*2.首页分类导航渲染*/ List<Map> categoryList = categoryService.findCategoryTree(); model.addAttribute("categoryList",categoryList); return "index"; } }
//根据广告位置查询广告列表 public List<Ad> findByPosition(String position) { //创建查询条件 Example example=new Example(Ad.class); Example.Criteria criteria = example.createCriteria(); criteria.andEqualTo("position",position); criteria.andLessThanOrEqualTo("startTime",new Date()); criteria.andGreaterThanOrEqualTo("endTime",new Date()); criteria.andEqualTo("status","1"); return adMapper.selectByExample(example); }
- ②. 使用thymeleaf怎么实现的
③. 首页分类导航渲染
3>. 首页分类导航渲染
首页分类导航的渲染: 拿到数据后,在模板页面中进行三次循环即可 [注意:这里前端要一个树状的结构,我们需要一个parentId的字段] 思路有两种: 1.通过parentId=0 查询得到一级菜单,遍历一级菜单,得到二级菜单,遍历二级菜单, 得到三级菜单,不推荐使用,因为和数据库需要频繁的交互,交互次数=1+一级菜单数量+二级菜单数量 2.首先把符合条件的记录(每一级菜单列表)[推荐使用]
//首页分类导航渲染 public List<Map> findCategoryTree() { Example example=new Example(Category.class); Example.Criteria criteria = example.createCriteria(); criteria.andEqualTo("isShow","1");//显示 example.setOrderByClause("seq");//排序 List<Category> categories = categoryMapper.selectByExample(example); return findByParentId(categories,0); } public List<Map> findByParentId(List<Category>categories,Integer parentId){ List<Map>listMap=new ArrayList<Map>(); for(Category category:categories){ if(category.getParentId().equals(parentId)){ Map map=new HashMap(); map.put("name",category.getName()); map.put("menus",findByParentId(categories,category.getId())); listMap.add(map); } } return listMap; }
④. 商品详细页静态渲染
4>. 商品详细页静态渲染
- ①. 为什么使用静态渲染而不用动态渲染?
- ②. 核心代码实现[主要掌握配置静态化的过程]
@RestController @RequestMapping("/item") public class ItemController { @Reference private SpuService spuService; @Reference private CategoryService categoryService; @Value("${pagePath}") private String pagePath; @Autowired private TemplateEngine templateEngine; @GetMapping("/createPage") public void createPage(String spuId){ //1.查询商品信息 Goods goods = spuService.findGoodsById(spuId); // 获取spu信息 Spu spu = goods.getSpu(); // 获取sku列表 List<Sku> skuList = goods.getSkuList(); //查询商品分类 List<String> categoryList=new ArrayList<>(); categoryList.add( categoryService.findById(spu.getCategory1Id()).getName() );//一级分类 categoryList.add( categoryService.findById(spu.getCategory2Id()).getName() );//二级分类 categoryList.add( categoryService.findById(spu.getCategory3Id()).getName() );//三级分类 //sku地址列表 Map<String,String> urlMap=new HashMap<>(); for(Sku sku:skuList){ if("1".equals(sku.getStatus())){ String specJson = JSON.toJSONString( JSON.parseObject(sku.getSpec()), SerializerFeature.MapSortField); urlMap.put(specJson,sku.getId()+".html"); } } //2.批量生成sku页面 for(Sku sku:skuList){ //(1) 创建上下文和数据模型 Context context=new Context(); Map<String,Object> dataModel= new HashMap<>(); dataModel.put("spu",spu); dataModel.put("sku",sku); dataModel.put("categoryList",categoryList); dataModel.put("skuImages", sku.getImages().split(",") );//sku图片列表 dataModel.put("spuImages", spu.getImages().split(",") );//spu图片列表 Map paraItems= JSON.parseObject( spu.getParaItems());//参数列表 dataModel.put("paraItems",paraItems); Map<String,String> specItems = (Map)JSON.parseObject(sku.getSpec());//规格列表 当前sku dataModel.put("specItems",specItems); //{"颜色":["天空之境","珠光贝母"],"内存":["8GB+64GB","8GB+128GB","8GB+256GB"]} //{"颜色":[{ 'option':'天空之境',checked:true },{ 'option':'珠光贝母',checked:false }],.....} Map<String,List> specMap = (Map)JSON.parseObject(spu.getSpecItems());//规格和规格选项 for(String key :specMap.keySet() ){ //循环规格 List<String> list = specMap.get(key);//["天空之境","珠光贝母"] List<Map> mapList=new ArrayList<>();//新的集合 //[{ 'option':'天空之境',checked:true },{ 'option':'珠光贝母',checked:false }] //循环规格选项 for(String value:list){ Map map=new HashMap(); map.put("option",value);//规格选项 if(specItems.get(key).equals(value) ){ // 如果和当前sku的规格相同,就是选中 map.put("checked",true);//是否选中 }else{ map.put("checked",false);//是否选中 } Map<String,String> spec= (Map)JSON.parseObject(sku.getSpec()) ;//当前的Sku spec.put(key,value); String specJson = JSON.toJSONString(spec , SerializerFeature.MapSortField); map.put("url",urlMap.get(specJson)); mapList.add(map); } specMap.put(key,mapList);//用新的集合替换原有的集合 } dataModel.put("specMap" ,specMap); context.setVariables(dataModel); //(2)准备文件 File dir =new File(pagePath); if( !dir.exists()){ dir.mkdirs(); } File dest= new File(dir, sku.getId()+".html" ); //(3)生成页面 try { PrintWriter writer=new PrintWriter( dest,"UTF-8"); templateEngine.process("item",context,writer ); System.out.println("生成页面:"+sku.getId()+".html"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } }