新建banner微服务
# 服务端口
server.port=8004
# 服务名
spring.application.name=service-cms
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/school?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/alex/educms/mapper/xml/*.xml
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
@SpringBootApplication
@ComponentScan({"com.alex"}) //指定扫描位置
@MapperScan("com.alex.educms.mapper")
public class CmsApplication {
public static void main(String[] args) {
SpringApplication.run(CmsApplication.class, args);
}
}
创建banner服务接口
@RestController
@RequestMapping("/educms/banneradmin")
@CrossOrigin
public class BannerAdminController {
@Autowired
private CrmBannerService bannerService;
// 1. 分页查询banner
@GetMapping("pageBanner/{page}/{limit}")
public R pageBanner(@PathVariable long page, @PathVariable long limit) {
Page<CrmBanner> pageBanner = new Page<>(page, limit);
bannerService.page(pageBanner,null);
return R.ok().data("items", pageBanner.getRecords()).data("total", pageBanner.getTotal());
}
// 2. 添加banner
@PostMapping("addBanner")
public R addBanner(@RequestBody CrmBanner crmBanner) {
bannerService.save(crmBanner);
return R.ok();
}
// 3. 修改banner
@PutMapping("update")
public R updateById(@RequestBody CrmBanner banner) {
bannerService.updateById(banner);
return R.ok();
}
// 4. 删除banner
@DeleteMapping("remove/{id}")
public R remove(@PathVariable String id) {
bannerService.removeById(id);
return R.ok();
}
// 5. 获取banner
@GetMapping("get/{id}")
public R get(@PathVariable String id) {
CrmBanner banner = bannerService.getById(id);
return R.ok().data("item", banner);
}
}
@RestController
@RequestMapping("/educms/bannerfront")
@CrossOrigin
public class BannerFrontController {
@Autowired
private CrmBannerService bannerService;
// 查询所有banner
@GetMapping("getAllBanner")
public R getAllBanner() {
List<CrmBanner> list = bannerService.selectAllBanner();
return R.ok().data("list", list);
}
}
public interface CrmBannerService extends IService<CrmBanner> {
List<CrmBanner> selectAllBanner();
}
@Service
public class CrmBannerServiceImpl extends ServiceImpl<CrmBannerMapper, CrmBanner> implements CrmBannerService {
@Override
public List<CrmBanner> selectAllBanner() {
List<CrmBanner> list = baseMapper.selectList(null);
return list;
}
}
@RestController
@RequestMapping("/eduservice/indexfront")
@CrossOrigin
public class IndexFrontController {
@Autowired
private EduCourseService courseService;
@Autowired
private EduTeacherService teacherService;
// 查询前8条热门课程,查询前4个名师
@GetMapping("index")
public R index() {
// 查询前8条热门课程
QueryWrapper<EduCourse> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
wrapper.last("limit 8");
List<EduCourse> eduList = courseService.list(wrapper);
// 查询前4个名师
QueryWrapper<EduTeacher> wrapperTeacher = new QueryWrapper<>();
wrapperTeacher.orderByDesc("id");
wrapperTeacher.last("limit 4");
List<EduTeacher> teacherList = teacherService.list(wrapperTeacher);
return R.ok().data("eduList",eduList).data("teacherList", teacherList);
}
}
// api\banner.js
import request from '@/utils/request'
export default {
// 查询前两条banner数据
getListBanner() {
return request({
url: `/educms/bannerfront/getAllBanner`,
method: 'get'
})
}
}
// utils\request.js
import axios from 'axios'
// 创建axios实例
const service = axios.create({
baseURL: 'http://localhost:9001', // api的base_url
timeout: 20000 // 请求超时时间
})
export default service
// pages\index.vue
<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>
import banner from '@/api/banner'
export default {
data () {
return {
bannerList: []
}
},
created() {
// 调用查询banner的方法
this.getBannerList()
},
methods: {
// 查询banner数据
getBannerList() {
banner.getListBanner()
.then(response => {
this.bannerList = response.data.data.list
})
}
}
}
script>
// api\index.js
import request from '@/utils/request'
export default {
// 查询热门课程和名师
getIndexData() {
return request({
url: `/eduservice/indexfront/index`,
method: 'get'
})
}
}
// pages\index.vue
<div id="aCoursesList">
<div>
<section class="container">
<header class="comm-title">
<h2 class="tac">
<span class="c-333">热门课程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="开始学习" class="comm-btn c-btn-1">开始学习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">免费i>
span>
<span class="fl jgAttr c-ccc f-fA">
<i class="c-999 f-fA">9634人学习i>
|
<i class="c-999 f-fA">9634评论i>
span>
section>
div>
li>
ul>
<div class="clear">div>
article>
<section class="tac pt20">
<a href="#" title="全部课程" class="comm-btn c-btn-2">全部课程a>
section>
div>
section>
div>
<div>
<section class="container">
<header class="comm-title">
<h2 class="tac">
<span class="c-333">名师大咖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="全部讲师" class="comm-btn c-btn-2">全部讲师a>
section>
div>
section>
div>
div>
<script>
import banner from '@/api/banner'
import index from '@/api/index'
export default {
data () {
return {
bannerList: [],
eduList: [],
teacherList: []
}
},
created() {
// 调用查询banner的方法
this.getBannerList(),
// 调用查询热门课程和名师的方法
this.getHotCourseTeacher()
},
methods: {
// 查询热门课程和名师
getHotCourseTeacher() {
index.getIndexData()
.then(response => {
this.eduList = response.data.data.eduList
this.teacherList = response.data.data.teacherList
})
},
// 查询banner数据
getBannerList() {
banner.getListBanner()
.then(response => {
this.bannerList = response.data.data.list
})
}
}
}
script>
Redis是当前比较热门的NOSQL系统之一,它是一个开源的使用ANSI c语言编写的key-value存储系统(区别于MySQL的二维表格的形式存储。)。和Memcache类似,但很大程度补偿了Memcache的不足。和Memcache一样,Redis数据都是缓存在计算机内存中,不同的是,Memcache只能将数据缓存到内存中,无法自动定期写入硬盘,这就表示,一断电或重启,内存清空,数据丢失。所以Memcache的应用场景适用于缓存无需持久化的数据。而Redis不同的是它会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,实现数据的持久化。
Redis的特点:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
<version>2.6.0version>
dependency>
package com.alex.servicebase;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
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;
/**
* @author :alex
* @date :Created in 2022/2/27
* @description :
* @version: 1.0
*/
@Configuration // 配置类
@EnableCaching // 开启缓存
public class RedisConfig extends CachingConfigurerSupport {
@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.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
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;
}
}
(1)缓存@Cacheable
根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。
查看源码,属性值如下:
属性/方法名 | 解释 |
---|---|
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与 value 差不多,二选一即可 |
key | 可选属性,可以使用 SpEL 标签自定义缓存的key |
(2)缓存@CachePut
使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。
查看源码,属性值如下:
属性/方法名 | 解释 |
---|---|
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与 value 差不多,二选一即可 |
key | 可选属性,可以使用 SpEL 标签自定义缓存的key |
(3)缓存@CacheEvict
使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上
查看源码,属性值如下:
属性/方法名 | 解释 |
---|---|
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与 value 差不多,二选一即可 |
key | 可选属性,可以使用 SpEL 标签自定义缓存的key |
allEntries | 是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存 |
beforeInvocation | 是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存 |
连接redis服务可能遇到的问题
banner接口改造
spring.redis.host=192.168.44.132
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
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
@Service
public class CrmBannerServiceImpl extends ServiceImpl<CrmBannerMapper, CrmBanner> implements CrmBannerService {
// 查询所有banner
@Cacheable(key = "'selectIndexList'", value = "banner")
@Override
public List<CrmBanner> selectAllBanner() {
// 根据id进行降序排列,显示排列之后前两条记录
QueryWrapper<CrmBanner> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
// last方法,拼接sql语句
wrapper.last("limit 2");
List<CrmBanner> list = baseMapper.selectList(wrapper);
return list;
}
}