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"> </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"> </em> </a> <q class="red-point" style="display: none"> </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"> </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 name | explain |
---|---|
value | Cache name, required. It specifies the namespace in which your cache is stored |
cacheNames | Similar to value, just choose one from two |
key | Optional 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 name | explain |
---|---|
value | Cache name, required. It specifies the namespace in which your cache is stored |
cacheNames | Similar to value, just choose one from two |
key | Optional 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 name | explain |
---|---|
value | Cache name, required. It specifies the namespace in which your cache is stored |
cacheNames | Similar to value, just choose one from two |
key | Optional attribute. You can customize the cached key using the spiel tag |
allEntries | Whether to clear all caches. The default is false. If true is specified, all caches will be cleared immediately after the method is called |
beforeInvocation | Whether 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; }