1. 程式人生 > >電商入口網站商品品類多級聯動SpringBoot+Thymeleaf實現

電商入口網站商品品類多級聯動SpringBoot+Thymeleaf實現

在淘寶、京東等電商網站,其入口網站都有一個商品品類的多級聯動,滑鼠移動,就顯示,因為前端不是我做的,所以不說明前端實現,只介紹後端實現。

搭建部署SpringBoot環境
配置檔案配置:
開啟了對Thymeleaf模組引擎的支援

server:
  port: 8081
#logging:
#  config: classpath:logback_spring.xml
#  level:
#    com.muses.taoshop: debug
#  path: /data/logs

spring:
  datasource:

    # 主資料來源
    shop:
      url: jdbc:mysql://127.0.0.1:3306/taoshop?autoReconnect=true&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false
      username: root
      password: root

    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    # 連線池設定
    druid:
      initial-size: 5
      min-idle: 5
      max-active: 20
      # 配置獲取連線等待超時的時間
      max-wait: 60000
      # 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒
      time-between-eviction-runs-millis: 60000
      # 配置一個連線在池中最小生存的時間,單位是毫秒
      min-evictable-idle-time-millis: 300000
      # Oracle請使用select 1 from dual
      validation-query: SELECT 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      # 開啟PSCache,並且指定每個連線上PSCache的大小
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      # 配置監控統計攔截的filters,去掉後監控介面sql無法統計,'wall'用於防火牆
      filters: stat,wall,slf4j
      # 通過connectProperties屬性來開啟mergeSql功能;慢SQL記錄
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      # 合併多個DruidDataSource的監控資料
      use-global-data-source-stat: true

#  jpa:
#    database: mysql
#    hibernate:
#      show_sql: true
#      format_sql: true
#      ddl-auto: none
#      naming:
#        physical-strategy: org.hibernate.boot.entity.naming.PhysicalNamingStrategyStandardImpl

#  mvc:
#    view:
#      prefix: /WEB-INF/jsp/
#      suffix: .jsp

  #新增Thymeleaf配置
  thymeleaf:
    cache: false
    prefix: classpath:/templates/
    suffix: .html
    mode: HTML5
    encoding: UTF-8
    content-type: text/html

  #Jedis配置
#  jedis :
#    pool :
#      host : 127.0.0.1
#      port : 6379
#      password : redispassword
#      timeout : 0
#      config :
#        maxTotal : 100
#        maxIdle : 10
#        maxWaitMillis : 100000

SpringBoot啟動類:

package com.muses.taoshop;



import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.*;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.*;
/**
 *
 * <pre>
 *  SpringBoot啟動配置類
 * </pre>
 * @author nicky
 * @version 1.00.00
 * <pre>
 * 修改記錄
 *    修改後版本:     修改人:  修改日期:     修改內容:
 * </pre>
 */
@Controller
@EnableScheduling//開啟對計劃任務的支援
@EnableTransactionManagement//開啟對事務管理配置的支援
@EnableCaching
@EnableAsync//開啟對非同步方法的支援
@EnableAutoConfiguration
@ServletComponentScan
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,
        MybatisAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class})
public class PortalApplication {

    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "portal web!";
    }

    @RequestMapping("/doTest")
    @ResponseBody
    String doTest(){
        System.out.println(Thread.currentThread().getName());
        String threadName = Thread.currentThread().getName();
        return threadName;
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(PortalApplication.class, args);
    }
}

寫個Controller類跳轉到入口網站:
ps:品類多級聯動思路其實就是先構建一個樹,我這裡的做法就是先查詢處理,然後通過工具類,進行遞迴遍歷,待會給出工具類程式碼,僅供參考。listCategory方法其實就是獲取所有的品類資訊

package com.muses.taoshop.web.controller.portal;

import com.alibaba.fastjson.JSON;
import com.muses.taoshop.item.entity.ItemBrand;
import com.muses.taoshop.item.entity.ItemCategory;
import com.muses.taoshop.item.entity.ItemPortal;
import com.muses.taoshop.item.service.IItemBrankService;
import com.muses.taoshop.item.service.IItemCategoryService;
import com.muses.taoshop.item.service.IItemService;
import com.muses.taoshop.util.CategoryTreeUtils;
import com.muses.taoshop.web.controller.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;
import java.util.List;

/**
 * <pre>
 *  入口網站控制類
 * </pre>
 *
 * @author nicky
 * @version 1.00.00
 * <pre>
 * 修改記錄
 *    修改後版本:     修改人:  修改日期:     修改內容:
 * </pre>
 */
@Controller
@RequestMapping("/portal")
public class IndexController extends BaseController{

    @Autowired
    IItemService iItemService;
    @Autowired
    IItemBrankService iItemBrankService;
    @Autowired
    IItemCategoryService iItemCategoryService;

    /**
     * 跳轉到入口網站
     * @return
     */
    @GetMapping(value = "/toIndex.do")
    public ModelAndView toIndex(){
        info("跳轉到入口網站");
        ModelAndView mv = this.getModelAndView();
        mv.setViewName("index");
        List<ItemPortal> items = iItemService.listItemPortal();
        CategoryTreeUtils treeUtil = new CategoryTreeUtils();
        List<ItemCategory> list = iItemCategoryService.listCategory();
        List<ItemCategory> categories = treeUtil.buildCategoryTree(list);
        mv.addObject("items" , items);
        mv.addObject("categories" , categories);
        return mv;
    }

    @GetMapping(value = "/doTest")
    @ResponseBody
    public  String doTest(){
        List<ItemBrand> itemBrands = iItemBrankService.listItemBrand();
        String str = JSON.toJSON(itemBrands).toString();
        return str;
    }


}

業務介面類:

 package com.muses.taoshop.item.service;

import com.muses.taoshop.item.entity.ItemCategory;
import com.muses.taoshop.item.entity.ItemList;

import java.util.List;

/**
 * <pre>
 *  商品品類資訊介面
 * </pre>
 *
 * @author nicky
 * @version 1.00.00
 * <pre>
 * 修改記錄
 *    修改後版本:     修改人:  修改日期: 2018.06.17 10:59    修改內容:
 * </pre>
 */
public interface IItemCategoryService {
  
    /**
     * 查詢所有商品品類資訊
     * @return
     */
    List<ItemCategory> listCategory();

    

業務服務實現類:

  package com.muses.taoshop.item.service;

import com.muses.taoshop.item.entity.ItemCategory;
import com.muses.taoshop.item.entity.ItemList;
import com.muses.taoshop.item.mapper.ItemCategoryMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <pre>
 *  商品品類資訊服務實現類
 * </pre>
 *
 * @author nicky
 * @version 1.00.00
 * <pre>
 * 修改記錄
 *    修改後版本:     修改人:  修改日期: 2018.06.17 11:01    修改內容:
 * </pre>
 */
@Service
public class ItemCategoryServiceImpl implements IItemCategoryService{

    @Autowired
    ItemCategoryMapper itemCategoryMapper;


    /**
     * 查詢所有的商品品類資訊
     * @return
     */
    @Override
    public List<ItemCategory> listCategory() {
        return itemCategoryMapper.listCategory();
    }

 


}

Mybatis相關程式碼:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.muses.taoshop.item.mapper.ItemCategoryMapper" >
  <resultMap id="BaseResultMap" type="com.muses.taoshop.item.entity.ItemCategory" >
    <id column="id" property="id" jdbcType="BIGINT" />
    <result column="category_name" property="categoryName" jdbcType="VARCHAR" />
    <result column="sjid" property="sjid" jdbcType="BIGINT" />
    <result column="last_modify_time" property="lastModifyTime" jdbcType="TIMESTAMP" />
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
  </resultMap>

  <sql id="BaseColumnList" >
    id,
        category_name as categoryName,
        sjid,
        last_modify_time as lastModifyTime,
        create_time as createTime
  </sql>
  
    <!-- 獲取所有的商品品類資訊-->
    <select id="listCategory" resultType="ItemCategory">
        SELECT 
        <include refid="BaseColumnList" />
        FROM item_category t
    </select>
    
</mapper>

Mapper介面類:

package com.muses.taoshop.item.mapper;

import com.muses.taoshop.item.entity.ItemCategory;
import com.muses.taoshop.item.entity.ItemList;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
@Mapper
public interface ItemCategoryMapper {

    List<ItemCategory> listCategory();

   
}

實體類:
這裡用了lombok的jar來實現,所有不用set和get方法

package com.muses.taoshop.item.entity;


import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;

/**
 * <pre>
 *  商品品類
 * </pre>
 * @author nicky
 * @version 1.00.00
 * <pre>
 * 修改記錄
 *    修改後版本:     修改人:  修改日期: 2018.06.09 21:49    修改內容:
 * </pre>
 */
@Data
public class ItemCategory {
    /**
     * 商品品類id
     */
    private Long id;

    /**
     * 商品品類名稱
     */
    private String categoryName;

    /**
     * 上級id
     */
    private Long sjid;

    /**
     * 上次修改時間
     */
    @JSONField(format ="yyyy-MM-dd HH:mm:ss")
    private Date lastModifyTime;

    /**
     * 建立時間
     */
    @JSONField(format ="yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    /**
     * 子選單
     */
    private List<ItemCategory> subCategorys;


}

構建品類樹的工具類:

package com.muses.taoshop.util;

import com.muses.taoshop.item.entity.ItemCategory;

import javax.mail.FetchProfile;
import java.util.ArrayList;
import java.util.List;

/**
 * <pre>
 *  構造一棵品類樹
 * </pre>
 *
 * @author nicky
 * @version 1.00.00
 * <pre>
 * 修改記錄
 *    修改後版本:     修改人:  修改日期: 2018.06.24 17:12    修改內容:
 * </pre>
 */
public class CategoryTreeUtils {


    public List<ItemCategory> commonCategorys;

    public List<ItemCategory> list = new ArrayList<ItemCategory>();

    public List<ItemCategory> buildCategoryTree(List<ItemCategory> categories ) {
        this.commonCategorys = categories;
        for (ItemCategory c : categories){
            ItemCategory category = new ItemCategory();
            if(c.getSjid() == 0){
                category.setSjid(c.getSjid());
                category.setId(c.getId());
                category.setCategoryName(c.getCategoryName());
                category.setSubCategorys(treeChild(c.getId()));
                list.add(category);
            }
        }
        return list;
    }

    public List<ItemCategory> treeChild(long id){
        List<ItemCategory> list = new ArrayList<ItemCategory>();
        for(ItemCategory c : commonCategorys){
            ItemCategory category = new ItemCategory();
            if(c.getSjid() == id){
                category.setSjid(c.getSjid());
                category.setId(c.getId());
                category.setCategoryName(c.getCategoryName());
                category.setSubCategorys(treeChild(c.getId()));//遞迴迴圈
                list.add(category);
            }
        }
        return list;
    }
}

前端程式碼:

<div class="headerNav" xmlns:th="http://www.thymeleaf.org">
    <div class="layout">
        <dl class="all-brands">
            <dt class="all-brands-head"> <a href="#">全部商品分類</a> </dt>
            <dd class="all-brands-list">
                <div class="wrap" th:each="c : ${categories}">
                    <div class="all-sort-list">
                        <div class="item bo">
                            <h3>
                                <a href="" th:text="${c.categoryName}"></a></h3>
                            <div class="item-list clearfix">
                                <div class="close">x</div>
                                <div class="subitem" th:each="s: ${c.subCategorys}">
                                    <dl class="fore1">
                                        <dt th:text="${s.categoryName}"><a th:href="@{'/portal/category/toCategoryList/'+${s.id}}"></a></dt>
                                        <dd>
                                            <em th:each="ss : ${s.subCategorys} "><a th:href="@{'/portal/category/toCategoryList/'+${ss.id}}" th:text="${ss.categoryName}"></a></em>
                                        </dd>
                                    </dl>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </dd>
            
        </dl>
      
        </div>
    </div>
</div>

實現的效果如圖:可以說是3級聯動
在這裡插入圖片描述

這是在開發中的開源專案的一個小功能,原始碼已經開源,github連結