Banner微服务
配置 Nginx
修改文件:nginx.conf
修改完后,重启 nginx
nginx -s reload
创建项目和初始化
1、新建模块
service_cms
2、配置文件和启动类
创建配置文件:application.properties
# 服务端口
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/guli?useSSL=false&useUnicode=true&characterEncoding=UTF-8&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/atguigu/educms/mapper/xml/*.xml
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
创建包org.jyunkai.educms,启动类CmsApplication
@SpringBootApplication
@ComponentScan({"com.atguigu"})
@MapperScan("com.atguigu.educms.mapper")
public class CmsApplication {
public static void main(String[] args) {
SpringApplication.run(CmsApplication.class, args);
}
}
3、代码生成器
复制service_edu模块中的CodeGenerator类,更改模块名称为educms,更改表名为crm_banner,运行即可。
public class CodeGenerator {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir("D:\\java\\springcloud\\guli_xueyuan\\guli_parent\\service\\service_cms" + "/src/main/java");
gc.setAuthor("testjava");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
//UserServie
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键策略
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("educms"); //模块名
//包 com.atguigu.eduservice
pc.setParent("com.atguigu");
//包 com.atguigu.eduservice.controller
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("crm_banner");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
创建banner后台管理接口
banner 后台分页查询、添加、修改、删除接口
controller层
删除 CrmBannerController,新建后台管理接口:
@RestController
@RequestMapping("/educms/banneradmin")
@CrossOrigin
public class BannerAdminController {
@Autowired
private CrmBannerService bannerService;
@ApiOperation(value = "获取Banner分页列表")
@GetMapping("pageBanner/{page}/{limit}")
public R pageBanner(
@ApiParam(name = "page", value = "当前页码", required = true)
@PathVariable("page") Long page,
@ApiParam(name = "limit", value = "每页记录数", required = true)
@PathVariable("limit") Long limit) {
Page<CrmBanner> pageBanner = new Page<>(page, limit);
bannerService.page(pageBanner, null);
return R.ok().data("items", pageBanner.getRecords()).data("total", pageBanner.getTotal());
}
@ApiOperation(value = "获取Banner")
@GetMapping("get/{id}")
public R get(@PathVariable("id") String id) {
CrmBanner banner = bannerService.getBannerById(id);
return R.ok().data("item", banner);
}
@ApiOperation(value = "新增Banner")
@PostMapping("save")
public R save(@RequestBody CrmBanner banner) {
bannerService.saveBanner(banner);
return R.ok();
}
@ApiOperation(value = "修改Banner")
@PutMapping("update")
public R updateById(@RequestBody CrmBanner banner) {
bannerService.updateBannerById(banner);
return R.ok();
}
@ApiOperation(value = "删除Banner")
@DeleteMapping("remove/{id}")
public R remove(@PathVariable("id") String id) {
bannerService.removeBannerById(id);
return R.ok();
}
}
创建banner前台管理接口
controller层
创建类BannerFrontController
@RestController
@RequestMapping("/educms/bannerfront")
@CrossOrigin
public class BannerFrontController {
@Autowired
private CrmBannerService bannerService;
@ApiOperation(value = "查询所有的banner")
@GetMapping("getAllBanner")
public R getAllBanner() {
List<CrmBanner> list = bannerService.selectAllBanner();
return R.ok().data("list", list);
}
}
service层
public interface CrmBannerService extends IService<CrmBanner> {
// 查询所有的banner
List<CrmBanner> selectAllBanner();
}
实现类
@Service
public class CrmBannerServiceImpl extends ServiceImpl<CrmBannerMapper, CrmBanner> implements CrmBannerService {
// 查询所有的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(null);
return list;
}
}
前端查询课程名师接口
在 service_edu 模块
controller层
创建front包,然后创建IndexFrontController类:
@RestController
@RequestMapping("/eduservice/indexfront")
@CrossOrigin
public class IndexFrontController {
@Autowired
private EduCourseService courseService;
@Autowired
private EduTeacherService teacherService;
/*
查询前8条热门课程,前4条热门名师
*/
@GetMapping("index")
public R index() {
QueryWrapper<EduCourse> courseWrapper = new QueryWrapper<>();
courseWrapper.orderByDesc("id");
courseWrapper.last("limit 8");
List<EduCourse> courseList = courseService.list(courseWrapper);
QueryWrapper<EduTeacher> teacherWrapper = new QueryWrapper<>();
teacherWrapper.orderByDesc("id");
teacherWrapper.last("limit 4");
List<EduTeacher> teacherList = teacherService.list(teacherWrapper);
return R.ok().data("courseList", courseList).data("teacherList", teacherList);
}
}
前端部分
1、js
在根目录下创建一个api文件夹,在里面新建 banner.js 和 index.js
banner.js:
import request from '../utils/request'
export default {
// 查询前两条 banner 数据
getListBanner() {
return request({
url: '/educms/bannerfront/getAllBanner',
method: 'get'
})
}
}
index.js:
import request from '../utils/request'
export default {
// 查询热门课程和名师
getIndexData() {
return request({
url: '/eduservice/indexfront/index',
method: 'get'
})
}
}
2、pages/index.vue
定义和调用方法
<script>
import banner from '../api/banner'
import index from '../api/index'
export default {
data() {
return {
swiperOption: {
//配置分页
pagination: {
el: '.swiper-pagination'//分页的dom节点
},
//配置导航
navigation: {
nextEl: '.swiper-button-next',//下一页dom节点
prevEl: '.swiper-button-prev'//前一页dom节点
}
},
//banner数组
bannerList: [],
eduList: [],
teacherList: []
}
},
created() {
//调用查询banner的方法
this.getBannerList()
//调用查询热门课程和名师的方法
this.getHotCourseTeacher()
},
methods: {
//查询热门课程和名师
getHotCourseTeacher() {
index.getIndexData()
.then(response => {
this.eduList = response.data.data.eduList
console.log(this.eduList)
this.teacherList = response.data.data.teacherList
})
},
//查询banner数据
getBannerList() {
banner.getListBanner()
.then(response => {
this.bannerList = response.data.data.list
})
}
}
}
</script>
显示banner
修改数据库crm_banner表中的测试图片banner的链接:
http://guli.shop/photo/banner/1525939573202.jpg
http://guli.shop/photo/course/02.jpg
修改幻灯片播放代码:
<!-- 幻灯片 开始 -->
<div class="swiper-wrapper">
<div v-for="banner in bannerList" :key="banner.id" class="swiper-slide" style="background: #040B1B;">
<a :href="banner.linkUrl" target="_blank">
<img :src="banner.imageUrl" :alt="banner.title">
</a>
</div>
</div>
<!-- 幻灯片 结束 -->
课程列表部分(这里我加入了评论数和价格)
删去其它
- 标签,只保留一个
-
<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" style="width: 267.5px; height: 180px;"> <div class="cc-mask"> <a :href="'/course/' + course.id" title="开始学习" class="comm-btn c-btn-1">开始学习</a> </div> </section> <h3 class="hLh30 txtOf mt10"> <a :href="'/course/' + course.id" :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 fsize18 f-fA">免费</i> </span> <span class="fr jgTag bg-green" v-else style="background-color: red;"> <i class="c-fff fsize18 f-fA">¥{{ course.price }}</i> </span> <span class="fl jgAttr c-ccc f-fA"> <i class="c-999 f-fA">{{ course.viewCount }}人学习</i> | <i class="c-999 f-fA">{{ course.commentCount }}人评论</i> </span> </section> </div> </li>
讲师列表部分
删去其它 - 标签,只保留一个
-
<li v-for="teacher in teacherList" :key="teacher.id"> <section class="i-teach-wrap"> <div class="i-teach-pic"> <a :title="teacher.name" href="/teacher/1"> <img :alt="teacher.name" :src="teacher.avatar" style="height: 141.3px"> </a> </div> <div class="mt10 hLh30 txtOf tac"> <a :title="teacher.name" href="/teacher/1" 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>
配置 Redis 缓存
Redis 是当前比较热门的 NOSQL 技术之一,它是一个开源的使用ANSI C语言编写的 key-value 存储系统 (区别于 MySQL 的二维表格的形式存储。)。和 Memcache 类似,但很大程度补偿了 Memcache 的不足。和Memcache一样,Redis数据都是缓存在计算机内存中,不同的是,Memcache只能将数据缓存到 内存中,无法自动定期写入硬盘,这就表示,一断电或重启,内存清空,数据丢失。所以Memcache的 应用场景适用于缓存无需持久化的数据。而Redis不同的是它会周期性的把更新的数据写入磁盘或者把修 改操作写入追加的记录文件,实现数据的持久化。
Redis的特点:
1,Redis读取的速度是110000次/s,写的速度是81000次/s;
2,原子 。Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
3,支持多种数据结构:string(字符串);list(列表);hash(哈希),set(集合);zset(有序集合)
4,持久化,集群部署
5,支持过期时间,支持事务,消息订阅创建配置类
由于redis缓存是公共应用,所以我们把依赖与配置添加到了common模块下面,在common模块pom.xml下添加以下依赖
<!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- spring2.X集成redis所需common-pool2 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.0</version> </dependency>
在 service_base 模块的包 config 下面创建类:
@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; } }
在接口中使用 redis
在查询所有banner的方法上面添加缓存注解:
**(1)缓存@Cacheable **
根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。
查看源码,属性值如下:
**(2)缓存@CachePut **
使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。
查看源码,属性值如下:
**(3)缓存@CacheEvict **
使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上
查看源码,属性值如下:
首页数据添加 redis 缓存
在 service_cms 模块中controller层中:
注意不要引用错包:import org.springframework.cache.annotation.Cacheable
修改配置文件
在 service_cms 的配置文件中,配置 redis
# 配置 redis spring.redis.host=127.0.0.1 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