Shangsi Valley grain college learning notes 8 -- integrate NUXT foreground page, and redis cache has been integrated

Keywords: Redis Spring Boot Spring Cloud Cache Project

Server side rendering technology NUXT

What is server-side rendering

Server side rendering, also known as SSR (Server Side Render), completes the content of the page on the server side, rather than obtaining data through AJAX on the client side.

The advantages of server-side rendering (SSR) are: better SEO, because the search engine crawler can directly view the fully rendered pages.

If your application initially displays the loading chrysanthemum diagram, and then obtains the content through Ajax, the crawling tool will not wait for the asynchronous completion before crawling the page content. In other words, if SEO is very important to your site and your page gets content asynchronously, you may need server-side rendering (SSR) to solve this problem.

In addition, using server-side rendering, we can obtain faster time-to-content without waiting for all JavaScript to download and execute, resulting in a better user experience. For those applications where "time-to-content is directly related to conversion rate", server-side rendering (SSR) is very important.

What is NUXT

Nuxt.js is a lightweight application framework based on Vue.js. It can be used to create server-side rendering (SSR) applications, and can also act as a static site engine to generate static site applications. It has the characteristics of elegant code structure layering and hot loading.

Download compressed package

https://github.com/nuxt-community/starter-template/archive/master.zip

decompression

Modify package.json

name, description and author (this must be modified, otherwise the project cannot be installed) should also be removed

"name": "guli",
  "version": "1.0.0",
  "description": "Front desk website of grain College",
  "author": "dyk",

Modify nuxt.config.js

head: {
    title: 'Grain College - Java video|HTML5 video|Front end video|Python video|Big data video-Get 10000 for self-study+Monthly salary IT Online video course, cereal powder support, old students recommend it for you',
    meta: [{
        charset: 'utf-8'
      },
      {
        name: 'viewport',
        content: 'width=device-width, initial-scale=1'
      },
      {
        hid: 'keywords',
        name: 'keywords',
        content: 'Grain College,IT Online video tutorial,Java video,HTML5 video,Front end video,Python video,Big data video'
      },
      {
        hid: 'description',
        name: 'description',
        content: 'Grain college is a leading university in China IT Online video learning platform, vocational education platform. So far,There are tens of thousands of online and offline learners in cereal college! Developed jointly with hundreds of well-known development teams Java,HTML5 Front end, big data Python And other video courses, which are well received by the majority of learners and IT Engineers are known as: the most suitable for self-study, the largest amount of code, the most cases, the most practical and the most cutting-edge technology in the industry IT Series of video courses!'
      }
    ],
    link: [{
      rel: 'icon',
      type: 'image/x-icon',
      href: '/favicon.ico'
    }]
  },

Run in command prompt terminal

npm install

NUXT directory structure

(1) Resource catalog assets

Used to organize non compiled static resources such as LESS, SASS, or JavaScript.

(2) Component directory components

Vue.js component for organizing applications. Nuxt.js will not extend and enhance the vue.js components in this directory, that is, these components will not have the characteristics of asyncData method like page components.

(3) Layout directory layouts

Layout components used to organize applications.

(4) Page directory pages

Used to organize the routing and view of applications. The Nuxt.js framework reads all. vue files in this directory and automatically generates the corresponding routing configuration.

(5) Plugin directory plugins

It is used to organize Javascript plug-ins that need to be run before the root vue.js application is instantiated.

(6) nuxt.config.js file

The nuxt.config.js file is used to organize the personalized configuration of the Nuxt.js application so as to override the default configuration.

Install slide plug-in

npm install Vue awesome wiper in P168 downloads the latest version 4.x, and version 3.1.3 is used in the video. You have downloaded it. Go to the package.json file and modify the corresponding component to version ^ 3.1.3. Just reinstall npm install

npm install vue-awesome-swiper@3.1.3

Configure plug-ins

Create a new file nuxt-wiper-plugin.js in the plugins folder, which contains

import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper/dist/ssr'


Vue.use(VueAwesomeSwiper)

Configure the plug-in in the nuxt.config.js file
Copy the plugins and css nodes to the module.exports node

plugins: [
    {
      src: '~/plugins/nuxt-swiper-plugin.js',
      ssr: false
    }

  ],

  css: [
    'swiper/dist/css/swiper.css'
  ],

Page layout

Copy static resources

Copy the css, img, js and photo directories in the static prototype to the assets directory
Copy favicon.ico to the static directory

Modify default.vue in the layouts directory, copy the first page from the static page, modify the resource path in the original file to ~ / assets /, and replace the content in the main content area with

default.vue

<template>
  <div class="in-wrap">
    <!-- Common header introduction -->
    <header id="header">
      <section class="container">
        <h1 id="logo">
          <a href="#"title =" grain College ">
            <img src="~/assets/img/logo.png" width="100%" alt="Grain College" />
          </a>
        </h1>
        <div class="h-r-nsl">
          <ul class="nav">
            <router-link to="/" tag="li" active-class="current" exact>
              <a>home page</a>
            </router-link>
            <router-link to="/course" tag="li" active-class="current">
              <a>curriculum</a>
            </router-link>
            <router-link to="/teacher" tag="li" active-class="current">
              <a>Famous teacher</a>
            </router-link>
            <router-link to="/article" tag="li" active-class="current">
              <a>article</a>
            </router-link>
            <router-link to="/qa" tag="li" active-class="current">
              <a>Q & A</a>
            </router-link>
          </ul>
          <!-- / nav -->
          <ul class="h-r-login">
            <li id="no-login">
              <a href="/sing_in" title="Sign in">
                <em class="icon18 login-icon">&nbsp;</em>
                <span class="vam ml5">Sign in</span>
              </a>
              |
              <a href="/sign_up" title="register">
                <span class="vam ml5">register</span>
              </a>
            </li>
            <li class="mr10 undis" id="is-login-one">
              <a href="#"title =" message "id =" headermsgcountid ">
                <em class="icon18 news-icon">&nbsp;</em>
              </a>
              <q class="red-point" style="display: none">&nbsp;</q>
            </li>
            <li class="h-r-user undis" id="is-login-two">
              <a href="#" title>
                <img
                  src="~/assets/img/avatar-boy.gif"
                  width="30"
                  height="30"
                  class="vam picImg"
                  alt
                />
                <span class="vam disIb" id="userName"></span>
              </a>
              <a
                href="javascript:void(0)"
                title="sign out"
                onclick="exit();"
                class="ml5"
                >sign out</a
              >
            </li>
            <!-- /Not logged in display page 1 li;After login, the 2nd and 3rd page will be displayed li -->
          </ul>
          <aside class="h-r-search">
            <form action="#" method="post">
              <label class="h-r-s-box">
                <input
                  type="text"
                  placeholder="Enter the course you want to study"
                  name="queryCourse.courseName"
                  value
                />
                <button type="submit" class="s-btn">
                  <em class="icon18">&nbsp;</em>
                </button>
              </label>
            </form>
          </aside>
        </div>
        <aside class="mw-nav-btn">
          <div class="mw-nav-icon"></div>
        </aside>
        <div class="clear"></div>
      </section>
    </header>
    <!-- /Common header introduction -->

    <nuxt />

    <!-- Common bottom introduction -->
    <footer id="footer">
      <section class="container">
        <div class>
          <h4 class="hLh30">
            <span class="fsize18 f-fM c-999">Links</span>
          </h4>
          <ul class="of flink-list">
            <li>
              <a href="http://Www.atguigu. COM / "title =" Shang Silicon Valley "target="_blank"
                >Shang Silicon Valley</a
              >
            </li>
          </ul>
          <div class="clear"></div>
        </div>
        <div class="b-foot">
          <section class="fl col-7">
            <section class="mr20">
              <section class="b-f-link">
                <a href="#"title =" about us "target =" _blank "> about us < / a >|
                <a href="#"title =" contact us "target ="_ Blank "> contact us < / a >|
                <a href="#"title =" help center "target =" _blank "> Help Center < / a >|
                <a href="#"title =" resource download "target =_ Blank "> resource download < / a >|
                <span>Service hotline: 010-56253825(Beijing) 0755-85293825(Shenzhen)</span>
                <span>Email: info@atguigu.com</span>
              </section>
              <section class="b-f-link mt10">
                <span>©2018 The copyright of the course belongs to grain college ICP Bei 17055252</span>
              </section>
            </section>
          </section>
          <aside class="fl col-3 tac mt15">
            <section class="gf-tx">
              <span>
                <img src="~/assets/img/wx-icon.png" alt />
              </span>
            </section>
            <section class="gf-tx">
              <span>
                <img src="~/assets/img/wb-icon.png" alt />
              </span>
            </section>
          </aside>
          <div class="clear"></div>
        </div>
      </section>
    </footer>
    <!-- /Common bottom introduction -->
  </div>
</template>
<script>
import "~/assets/css/reset.css";
import "~/assets/css/theme.css";
import "~/assets/css/global.css";
import "~/assets/css/web.css";

export default {};
</script>

Homepage index.vue

Modify pages/index.vue:
Modified the resource path in the original file to ~ / assets/

<template>
  
  <div>
    <!-- Slide start -->
  <div v-swiper:mySwiper="swiperOption">
      <div class="swiper-wrapper">

          <div v-for="banner in bannerList" :key="banner.id" class="swiper-slide" style="background: #040B1B;">
              <a target="_blank" :href="banner.linkUrl">
                  <img :src="banner.imageUrl" :alt="banner.title">
              </a>
          </div>
      </div>
      <div class="swiper-pagination swiper-pagination-white"></div>
      <div class="swiper-button-prev swiper-button-white" slot="button-prev"></div>
      <div class="swiper-button-next swiper-button-white" slot="button-next"></div>
  </div>
  <!-- End of slide -->
    
     <div id="aCoursesList">
      <!-- Start of online school course -->
      <div>
        <section class="container">
          <header class="comm-title">
            <h2 class="tac">
              <span class="c-333">Popular courses</span>
            </h2>
          </header>
          <div>
            <article class="comm-course-list">
              <ul class="of" id="bna">
                <li v-for="course in eduList" :key="course.id">
                  <div class="cc-l-wrap">
                    <section class="course-img">
                      <img
                        :src="course.cover"
                        class="img-responsive"
                        :alt="course.title"
                      >
                      <div class="cc-mask">
                        <a href="#"title =" start learning "class =" comm-btn c-btn-1 "> start learning</a>
                      </div>
                    </section>
                    <h3 class="hLh30 txtOf mt10">
                      <a href="#" :title="course.title" class="course-title fsize18 c-333">{{course.title}}</a>
                    </h3>
                    <section class="mt10 hLh20 of">
                      <span class="fr jgTag bg-green" v-if="Number(course.price) === 0">
                        <i class="c-fff fsize12 f-fA">free</i>
                      </span>
                      <span class="fl jgAttr c-ccc f-fA">
                        <i class="c-999 f-fA">9634 Human learning</i>
                        |
                        <i class="c-999 f-fA">9634 comment</i>
                      </span>
                    </section>
                  </div>
                </li>
               
              </ul>
              <div class="clear"></div>
            </article>
            <section class="tac pt20">
              <a href="#"title =" all courses "class =" comm-btn c-btn-2 "> all courses</a>
            </section>
          </div>
        </section>
      </div>
      <!-- /End of online course -->
      <!-- Start with famous teachers of online school -->
      <div>
        <section class="container">
          <header class="comm-title">
            <h2 class="tac">
              <span class="c-333">Famous teacher</span>
            </h2>
          </header>
          <div>
            <article class="i-teacher-list">
              <ul class="of">
                <li v-for="teacher in teacherList" :key="teacher.id">
                  <section class="i-teach-wrap">
                    <div class="i-teach-pic">
                      <a href="/teacher/1" :title="teacher.name">
                        <img :alt="teacher.name" :src="teacher.avatar">
                      </a>
                    </div>
                    <div class="mt10 hLh30 txtOf tac">
                      <a href="/teacher/1" :title="teacher.name" class="fsize18 c-666">{{teacher.name}}</a>
                    </div>
                    <div class="hLh30 txtOf tac">
                      <span class="fsize14 c-999">{{teacher.career}}</span>
                    </div>
                    <div class="mt15 i-q-txt">
                      <p
                        class="c-999 f-fA"
                      >{{teacher.intro}}</p>
                    </div>
                  </section>
                </li>
                
              </ul>
              <div class="clear"></div>
            </article>
            <section class="tac pt20">
              <a href="#"title =" all lecturers "class =" comm-btn c-btn-2 "> all lecturers</a>
            </section>
          </div>
        </section>
      </div>
      <!-- /End of famous teachers of online school -->
    </div>
  </div>
</template>

Slide plugin

<!-- Slide start -->
    <div v-swiper:mySwiper="swiperOption">
      <div class="swiper-wrapper">
        <div
          v-for="banner in bannerList"
          :key="banner.id"
          class="swiper-slide"
          style="background: #040b1b"
        >
          <a target="_blank" :href="banner.linkUrl">
            <img :src="banner.imageUrl" :alt="banner.title" />
          </a>
        </div>
      </div>
      <div class="swiper-pagination swiper-pagination-white"></div>
      <div
        class="swiper-button-prev swiper-button-white"
        slot="button-prev"
      ></div>
      <div
        class="swiper-button-next swiper-button-white"
        slot="button-next"
      ></div>
    </div>
<script>
export default {
  data () {
    return {
      swiperOption: {
        //Configure paging
        pagination: {
          el: '.swiper-pagination'//Paged dom node
        },
        //Configure navigation
        navigation: {
          nextEl: '.swiper-button-next',//Next page dom node
          prevEl: '.swiper-button-prev'//Previous dom node
        }
      }
    }
  }
}

</script>

route

Fixed route

Use router link to build a route. The address is / course
Create the course folder in the page directory and index.vue in the course directory

Dynamic routing

If we need to query a record by id, we need to use dynamic routing. The dynamic route of NUXT is a vue file starting with an underscore, and the parameter name is the file name after the underscore

Create in the course directory under pages_ id.vue

I have omitted too many other static pages, and it's troublesome to delete the serial number

banner data is displayed on the home page

Create a sub module service CMS under the service module

Execute sql script

configuration file

Generate banner code using code generator

In service_ Add in pom.xml of CMS

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
            <scope>test</scope>
        </dependency>
package codedemo;


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;

/**
 * @author
 * @since 2018/12/13
 */
public class CodeGenerator {

    @Test
    public void run() {

        // 1. Create code generator
        AutoGenerator mpg = new AutoGenerator();

        // 2. Global configuration
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir("D:\\ideacode\\guli_parent\\service\\service_cms" + "/src/main/java");

        gc.setAuthor("dyk");
        gc.setOpen(false); //Open Explorer after build
        gc.setFileOverride(false); //Whether the file is overwritten during regeneration

        //UserServie
        gc.setServiceName("%sService");	//Remove the initial I of the Service interface

        gc.setIdType(IdType.ASSIGN_ID); //Primary key policy
        gc.setDateType(DateType.ONLY_DATE);//Defines the date type in the generated entity class
        gc.setSwagger2(true);//Turn on Swagger2 mode

        mpg.setGlobalConfig(gc);

        // 3. Data source configuration
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/gulischool?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4. Package configuration
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("educms"); //Module name
        //Package com.atguigu.eduservice
        pc.setParent("com.atguigu");
        //Package com.atguigu.eduservice.controller
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5. Policy configuration
        StrategyConfig strategy = new StrategyConfig();

        strategy.setInclude("crm_banner");

        strategy.setNaming(NamingStrategy.underline_to_camel);//Naming policy for mapping database tables to entities
        strategy.setTablePrefix(pc.getModuleName() + "_"); //Remove table prefix when generating entities

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//Naming policy for mapping database table fields to entities
        strategy.setEntityLombokModel(true); // lombok model @ accessories (chain = true) setter chain operation

        strategy.setRestControllerStyle(true); //restful api style controller
        strategy.setControllerMappingHyphenStyle(true); //Hump to hyphen in url

        mpg.setStrategy(strategy);


        // 6. Execute
        mpg.execute();
    }
}

Create startup class

Create CmsApplication.java

@SpringBootApplication
@ComponentScan(basePackages = {"com.atguigu"})//Specify scan location
@MapperScan("com.atguigu.educms.mapper.CrmBannerMapper")
public class CmsApplication {
    public static void main(String[] args) {
        SpringApplication.run(CmsApplication.class,args);
    }
}

banner service interface

banner background management interface

banner background paging query, add, modify and delete interfaces

package com.atguigu.educms.controller;


import com.atguigu.commonutils.ResultVo;
import com.atguigu.educms.entity.CrmBanner;
import com.atguigu.educms.service.CrmBannerService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * <p>
 * Home banner table background
 * </p>
 *
 * @author dyk
 * @since 2021-09-27
 */
@RestController
@RequestMapping("/educms/banneradmin")
@CrossOrigin
public class BannerAdminController {

    @Autowired
    private CrmBannerService crmBannerService;
        //Paging query banner
    @GetMapping("pageBanner/{page}/{limt}")
    @ApiOperation(value = "obtain Banner Paging list")
    public ResultVo pageBanner(@PathVariable long page,@PathVariable long limit){
        Page<CrmBanner> crmBannerPage = new Page<CrmBanner>(page, limit);
        crmBannerService.page(crmBannerPage,null);
        return ResultVo.ok().data("items",crmBannerPage.getRecords()).data("total",crmBannerPage.getTotal());

    }
    //Add banner
    @ApiOperation(value = "newly added Banner")
    @PostMapping("/addBanner")
    public ResultVo addBanner(@RequestBody CrmBanner crmBanner){
        boolean save = crmBannerService.save(crmBanner);
        if(save){
            return ResultVo.ok();
        }
        else{
            return ResultVo.error();
        }
    }


    //Get information by id
    @ApiOperation(value = "obtain Banner")
    @GetMapping("get/{id}")
    public ResultVo getById(@PathVariable String id){
        CrmBanner crmBanner = crmBannerService.getById(id);
        return ResultVo.ok().data("item",crmBanner);
    }
    //Modify banner
    @PutMapping("update")
    @ApiOperation(value = "modify Banner")
    public ResultVo updateBanner(@RequestBody CrmBanner crmBanner){
        boolean b = crmBannerService.updateById(crmBanner);
        if(b){
            return ResultVo.ok();
        }
        else{
            return ResultVo.error();
        }
    }

    @DeleteMapping("remove/{id}")
    @ApiOperation(value = "delete Banner")
    public ResultVo remove(@PathVariable String id){
        boolean b = crmBannerService.removeById(id);
        if(b){
            return ResultVo.ok();
        }
        else{
            return ResultVo.error();
        }
    }
}


banner foreground query interface

@Autowired
    private CrmBannerService bannerService;
    //Query all banner s
    @GetMapping("getAllBanner")
    @ApiOperation(value = "Get home page banner")
    public ResultVo getAllBanner(){
      List<CrmBanner> list= bannerService.selectAllBanner();
      return ResultVo.ok().data("list",list);
    }

service

@Override
    public List<CrmBanner> selectAllBanner() {
        //Sort by id in descending order to display the first two records after arrangement
        QueryWrapper<CrmBanner> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        queryWrapper.last("limit 2");
        List<CrmBanner> list = baseMapper.selectList(null);
        return list;
    }

The home page displays the data of famous course teachers

back-end

Create the front package under the controller of the service edu module

@RestController
@CrossOrigin
@RequestMapping("/eduservice/indexfront")
public class IndexFrontController {

    @Autowired
    private EduCourseService courseService;
    @Autowired
    private EduTeacherService teacherService;

    //View the top 8 popular courses and the top 4 famous teachers
    @GetMapping("index")
    public ResultVo index(){
        QueryWrapper<EduCourse> courseQueryWrapper = new QueryWrapper<EduCourse>();
        courseQueryWrapper.orderByDesc("id");
        courseQueryWrapper.last("limit 8");
        List<EduCourse> courseList = courseService.list(courseQueryWrapper);
        
        QueryWrapper<EduTeacher> eduTeacherQueryWrapper = new QueryWrapper<>();
        eduTeacherQueryWrapper.orderByDesc("id");
        eduTeacherQueryWrapper.last("limit 4");
        List<EduTeacher> teacherList= teacherService.list(eduTeacherQueryWrapper);

        return ResultVo.ok().data("eduList",courseList).data("teacherList",teacherList);
    }
}

front end

Download axios

npm install axios

Encapsulating axios

Create the utils folder and create request.js under utils

import axios from 'axios'
// Create an axios instance

const service = axios.create({
  baseURL: 'http://Localhost: 9001 ', / / base of API_ url
  timeout: 20000 // Request timeout

})

export default service

Create the api folder and create the banner.js file

import request from '@/utils/request'

export default {
  //Query the first two banner data
  getListBanner() {
    return request({
      url: '/educms/bannerfront/getAllBanner',
      method: 'get'
    })
  }
}

<template>
  <div>
    <!-- Slide start -->
    <div v-swiper:mySwiper="swiperOption">
      <div class="swiper-wrapper">
        <div
          v-for="banner in bannerList"
          :key="banner.id"
          class="swiper-slide"
          style="background: #040b1b"
        >
          <a target="_blank" :href="banner.linkUrl">
            <img :src="banner.imageUrl" :alt="banner.title" />
          </a>
        </div>
      </div>
      <div class="swiper-pagination swiper-pagination-white"></div>
      <div
        class="swiper-button-prev swiper-button-white"
        slot="button-prev"
      ></div>
      <div
        class="swiper-button-next swiper-button-white"
        slot="button-next"
      ></div>
    </div>
    <!-- End of slide -->

    <div id="aCoursesList">
      <!-- Start of online school course -->
      <div>
        <section class="container">
          <header class="comm-title">
            <h2 class="tac">
              <span class="c-333">Popular courses</span>
            </h2>
          </header>
          <div>
            <article class="comm-course-list">
              <ul class="of" id="bna">
                <li v-for="course in eduList" :key="course.id">
                  <div class="cc-l-wrap">
                    <section class="course-img">
                      <img
                        :src="course.cover"
                        class="img-responsive"
                        :alt="course.title"
                      />
                      <div class="cc-mask">
                        <a href="#"title =" start learning "class="comm-btn c-btn-1“
                          >Start learning</a
                        >
                      </div>
                    </section>
                    <h3 class="hLh30 txtOf mt10">
                      <a
                        href="#"
                        :title="course.title"
                        class="course-title fsize18 c-333"
                        >{{ course.title }}</a
                      >
                    </h3>
                    <section class="mt10 hLh20 of">
                      <span
                        class="fr jgTag bg-green"
                        v-if="Number(course.price) === 0"
                      >
                        <i class="c-fff fsize12 f-fA">free</i>
                      </span>
                      <span class="fl jgAttr c-ccc f-fA">
                        <i class="c-999 f-fA">9634 Human learning</i>
                        |
                        <i class="c-999 f-fA">9634 comment</i>
                      </span>
                    </section>
                  </div>
                </li>
              </ul>
              <div class="clear"></div>
            </article>
            <section class="tac pt20">
              <a href="#"title =" all courses "class =" comm-btn c-btn-2 "> all courses</a>
            </section>
          </div>
        </section>
      </div>
      <!-- /End of online course -->
      <!-- Start with famous teachers of online school -->
      <div>
        <section class="container">
          <header class="comm-title">
            <h2 class="tac">
              <span class="c-333">Famous teacher</span>
            </h2>
          </header>
          <div>
            <article class="i-teacher-list">
              <ul class="of">
                <li v-for="teacher in teacherList" :key="teacher.id">
                  <section class="i-teach-wrap">
                    <div class="i-teach-pic">
                      <a href="/teacher/1" :title="teacher.name">
                        <img :alt="teacher.name" :src="teacher.avatar" />
                      </a>
                    </div>
                    <div class="mt10 hLh30 txtOf tac">
                      <a
                        href="/teacher/1"
                        :title="teacher.name"
                        class="fsize18 c-666"
                        >{{ teacher.name }}</a
                      >
                    </div>
                    <div class="hLh30 txtOf tac">
                      <span class="fsize14 c-999">{{ teacher.career }}</span>
                    </div>
                    <div class="mt15 i-q-txt">
                      <p class="c-999 f-fA">{{ teacher.intro }}</p>
                    </div>
                  </section>
                </li>
              </ul>
              <div class="clear"></div>
            </article>
            <section class="tac pt20">
              <a href="#"title =" all lecturers "class =" comm-btn c-btn-2 "> all lecturers</a>
            </section>
          </div>
        </section>
      </div>
      <!-- /End of famous teachers of online school -->
    </div>
  </div>
</template>

<script>
import banner from "@/api/banner";
import index from "@/api/index";

export default {
  data() {
    return {
      swiperOption: {
        //Configure paging
        pagination: {
          el: ".swiper-pagination", //Paged dom node
        },
        //Configure navigation
        navigation: {
          nextEl: ".swiper-button-next", //Next page dom node
          prevEl: ".swiper-button-prev", //Previous dom node
        },
      },
      //banner array
      bannerList: [],
      eduList: [],
      teacherList: [],
    };
  },
  created() {
    //Call the method to query the banner
    this.getBannerList();
    //Call the method to query popular courses and famous teachers
    this.getHotCourseTeacher();
  },
  methods: {
    //Query popular courses and famous teachers
    getHotCourseTeacher() {
      index.getIndexData().then((response) => {
        this.eduList = response.data.data.eduList;
        this.teacherList = response.data.data.teacherList;
      });
    },
    //Query banner data
    getBannerList() {
      banner.getListBanner().then((response) => {
        this.bannerList = response.data.data.list;
      });
    },
  },
};
</script>

Project integration Redis

Add dependency in common module

Since redis cache is a public application, we added the dependency and configuration under the common module, and added the following dependency under the common module pom.xml

<!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- spring2.X integrate redis what is needed common-pool2-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>

RedisConfig.java

package com.atguigu.servicebase.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurationSelector;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
@EnableCaching  //Enable cache
public class RedisConfig extends CachingConfigurationSelector {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
        //key serialization method
        template.setKeySerializer(redisSerializer);
        //value serialization
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //value hashmap serialization
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //Solve the problem of query cache conversion exception
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // Configure serialization (solve the problem of garbled code), and the expiration time is 600 seconds
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

Add redis cache in the interface

Because the home page data changes infrequently and the home page visits are relatively large, it is necessary to cache the home page interface data into the redis cache to reduce the database pressure and improve the access speed.

Transform the banner interface of the home page of the service CMS module, and the home page course is similar to the instructor interface

Spring Boot cache annotation

Cache @ Cacheable

Cache the returned results according to the method. In the next request, if the cache exists, directly read the cached data and return; if the cache does not exist, execute the method and store the returned results in the cache. It is generally used in query methods.

View the source code. The attribute values are as follows:

Property / method nameexplain
valueCache name, required. It specifies the namespace in which your cache is stored
cacheNamesSimilar to value, just choose one from two
keyOptional attribute. You can customize the cached key using the spiel tag

Cache @ CachePut

The method using this annotation flag will be executed every time and the results will be stored in the specified cache. Other methods can directly read the cached data from the response cache without querying the database. It is generally used for adding new methods.

View the source code. The attribute values are as follows:

Property / method nameexplain
valueCache name, required. It specifies the namespace in which your cache is stored
cacheNamesSimilar to value, just choose one from two
keyOptional attribute. You can customize the cached key using the spiel tag

Cache @ CacheEvict

The method using this annotation flag will empty the specified cache. It is generally used in update or delete methods

View the source code. The attribute values are as follows

Property / method nameexplain
valueCache name, required. It specifies the namespace in which your cache is stored
cacheNamesSimilar to value, just choose one from two
keyOptional attribute. You can customize the cached key using the spiel tag
allEntriesWhether to clear all caches. The default is false. If true is specified, all caches will be cleared immediately after the method is called
beforeInvocationWhether to empty before the method is executed. The default is false. If true is specified, the cache will be emptied before the method is executed

Start redis service

./redis-server myredisconfig/redisbak.conf 

Possible problems in connecting to redis service

1. Close the liunx firewall
2. Find the redis configuration file and comment the configuration line

# bind 127.0.0.1

3. Modify protected mode yes
Change to

protected-mode no

4. Set as daemon thread

daemonize yes

Add redis configuration in the service CMS module configuration file

spring.redis.host=124.57.252.81
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000

spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#Maximum blocking waiting time (negative number indicates no limit)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

Modify CrmBannerServiceImpl and add redis cache annotation

@Override
    @Cacheable(value = "banner",key="'selectIndexList'")
    public List<CrmBanner> selectAllBanner() {
        //Sort by id in descending order to display the first two records after arrangement
        QueryWrapper<CrmBanner> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        queryWrapper.last("limit 2");
        List<CrmBanner> list = baseMapper.selectList(null);
        return list;
    }

Posted by nagrgk on Mon, 04 Oct 2021 13:10:14 -0700