一、首页显示banner数据 – 前后台的后端
1、在service模块下创建子模块service-cms
2、使用代码生成器生成banner代码
(1)创建crm_banner表
(2)生成代码
3、配置application.yml
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #mybatis日志 mapper-locations: classpath:com/rg/cmsservice/mapper/xml/*.xml #配置mapper xml文件的路径 server: port: 8004 spring: application: name: service-cms datasource: # mysql数据库连接 driver-class-name: com.mysql.jdbc.Driver password: 186259 url: jdbc:mysql://localhost:3306/guli_edu username: root jackson: #返回json的全局时间格式 date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 cloud: #nacos服务地址 nacos: discovery: server-addr: 192.168.174.128:8848 redis: #redis相关配置 host: 192.168.174.128 port: 6379 database: 0 timeout: 1800000 lettuce: #最大阻塞等待时间 pool: max-active: 20 max-wait: -1 max-idle: 5 min-idle: 0
4、创建启动类
创建CmsApplication.java
@SpringBootApplication @ComponentScan("com.rg") @MapperScan("com.rg.cmsservice.mapper") public class CmsApplication { public static void main(String[] args) { SpringApplication.run(CmsApplication.class, args); } }
5、编写Controller
banner后台分页查询、添加、修改、删除接口
@RestController @RequestMapping("/cmsservice/banneradmin") @CrossOrigin public class CrmBannerAdminController { @Autowired private CrmBannerService bannerService; //查询轮播图列表 @PostMapping("pageQuery/{current}/{limit}") public R pageQuery(@PathVariable("current") Long current, @PathVariable("limit") Long limit,@RequestBody BannerQuery bannerQuery ){ Page <CrmBanner> page = bannerService.pageQuery(current,limit,bannerQuery); return R.ok().data("items",page.getRecords()).data("total",page.getTotal()); } //根据id获取 @GetMapping("getById/{id}") public R getById(@PathVariable("id") String id){ CrmBanner banner = bannerService.getById(id); return R.ok().data("banner",banner); } //增加一张轮播图 @PostMapping("addBanner") @CacheEvict(value = "banner", allEntries=true) public R addBanner(@RequestBody CrmBanner banner){ boolean flag = bannerService.save(banner); if(flag){ return R.ok(); }else{ return R.error(); } } //修改轮播图 @PutMapping("editBanner") @CacheEvict(value = "banner", allEntries=true) //当进行增删改时,清空banner缓存 public R editBanner(@RequestBody CrmBanner banner){ boolean flag = bannerService.updateById(banner); if(flag){ return R.ok(); }else{ return R.error(); } } //删除轮播图 @DeleteMapping("removeBanner/{id}") @CacheEvict(value = "banner", allEntries=true) public R removeBanner(@PathVariable("id") String id){ boolean flag = bannerService.removeById(id); if(flag){ return R.ok(); }else{ return R.error(); } } }
banner前台首页获取数据
@RestController @RequestMapping("/cmsservice/bannerfront") @CrossOrigin public class CrmBannerFrontController { @Autowired private CrmBannerService bannerService; //查询所有轮播图 @Cacheable(value = "banner",key="'bannerList'") @GetMapping("findAllBanner") public R findAllBanner(){ List <CrmBanner> bannerList = bannerService.findAll(); return R.ok().data("bannerList", bannerList); } }
6、编写Service
CrmBannerService
public interface CrmBannerService extends IService<CrmBanner> { List<CrmBanner> findAll(); //分页查询带条件 Page<CrmBanner> pageQuery(Long current, Long limit, BannerQuery bannerQuery); }
CrmBannerServiceImpl
@Service public class CrmBannerServiceImpl extends ServiceImpl<CrmBannerMapper, CrmBanner> implements CrmBannerService { //查询所有banner @Override public List <CrmBanner> findAll() { //根据sort排列,显示前两条记录 QueryWrapper <CrmBanner> wrapper = new QueryWrapper <>(); wrapper.orderByDesc("sort").last("limit 2");//last:拼接sql语句 List <CrmBanner> bannerList = this.baseMapper.selectList(wrapper); return bannerList; } //分页查询带条件 @Override public Page <CrmBanner> pageQuery(Long current, Long limit, BannerQuery bannerQuery) { Page <CrmBanner> page = new Page <>(current, limit); QueryWrapper <CrmBanner> wrapper = new QueryWrapper <>(); String title = bannerQuery.getTitle(); String linkUrl = bannerQuery.getLinkUrl(); String begin = bannerQuery.getBegin(); String end = bannerQuery.getEnd(); if(!StringUtils.isEmpty(title)){ wrapper.like("title",title); } if(!StringUtils.isEmpty(linkUrl)){ wrapper.like("link_url",linkUrl); } if(!StringUtils.isEmpty(begin)){ wrapper.ge("gmt_create", begin); } if(!StringUtils.isEmpty(end)){ wrapper.le("gmt_create", end); } //按照sort降序 wrapper.orderByDesc("sort"); this.baseMapper.selectPage(page, wrapper); return page; } }
8、首页显示课程名师数据
- 在service_edu 模块的Controller包下创建front包的IndexFrontController 类
@CrossOrigin @RestController @RequestMapping("/eduservice/index") public class IndexController { @Autowired private EduCourseService courseService; @Autowired private EduTeacherService teacherService; //查询前八条热门课程,前四条讲师记录 @GetMapping("findCourseAndTeacher") public R findCourseAndTeacher(){ List <EduCourse> courseList = courseService.findCourse(); List <EduTeacher> teacherList = teacherService.findTeacher(); return R.ok().data("courseList",courseList).data("teacherList",teacherList); } }
- EduCourseService类
//查询前8条热门课程(前台页面) @Override @Cacheable(value = "course",key="'courseList'") public List <EduCourse> findCourse() { //查询前8条热门课程 按照view_count,buy_count排序 QueryWrapper <EduCourse> courseWrapper = new QueryWrapper <>(); courseWrapper.orderByDesc("view_count","buy_count"); courseWrapper.last("limit 8"); // this.baseMapper.select List <EduCourse> courseList = this.baseMapper.selectList(courseWrapper); return courseList; }
- EduTeacherService类
//查询前四条讲师记录(前台页面) @Override @Cacheable(value = "teacher",key="'teacherList'") public List <EduTeacher> findTeacher() { QueryWrapper <EduTeacher> teacherWrapper = new QueryWrapper <>(); teacherWrapper.orderByDesc("sort"); teacherWrapper.last("limit 4"); List <EduTeacher> teacherList = this.baseMapper.selectList(teacherWrapper); return teacherList; }
二 、首页banner数据 – 后台的前端
实现banner后台的添加修改删除和分页查询操作,和其他后台管理模块类似
1、添加路由
{ path: '/banner', component: Layout, //布局 redirect: '/banner/table', name: '轮播图管理', meta: { title: '轮播图管理', icon: 'example' }, children: [{ path: 'list', name: '轮播图列表', component: () => import ('@/views/edu/banner/list'), meta: { title: '轮播图列表', icon: 'table' } }, { path: 'add', name: '添加轮播图', component: () => import ('@/views/edu/banner/add'), meta: { title: '添加轮播图', icon: 'tree' } }, { path: 'edit/:id', //隐藏路由的写法. :id类似于sql中的占位符,用来接收参数 name: '编辑轮播图', component: () => import ('@/views/edu/banner/add'), //因为修改和编辑使用同一个表单,所以使用同一个路由. meta: { title: '编辑轮播图', noCache: true }, hidden: true //将该路由进行隐藏,让用户看起来如同是在当前页面进行修改. } ] }
2、编写api接口—banner.js
import request from '@/utils/request' export default { //分页查询banner pageQuery(current,limit,bannerQuery) { return request({ url: `/cmsservice/banneradmin/pageQuery/${current}/${limit}`, method: 'post', data:bannerQuery }) }, //添加banner addBanner(banner){ return request({ url:`/cmsservice/banneradmin/addBanner`, method:`post`, data:banner }) }, //修改banner editBanner(banner){ return request({ url:`/cmsservice/banneradmin/editBanner`, method:`put`, data:banner }) }, //删除banner removeBanner(id){ return request({ url:`/cmsservice/banneradmin/removeBanner/${id}`, method:`delete` }) }, //通过id进行查询 getById(id){ return request({ url:`/cmsservice/banneradmin/getById/${id}`, method:'get' }) } }
3、编写list.vue页面
<template> <div class="app-container"> <!--查询条件 --> <el-form :inline="true" class="demo-form-inline"> <el-form-item> <el-input v-model="bannerQuery.title" placeholder="标题"/> </el-form-item> <el-form-item> <el-input v-model="bannerQuery.linkUrl" placeholder="链接地址"/> </el-form-item> <el-form-item label="添加时间"> <el-date-picker v-model="bannerQuery.begin" type="datetime" placeholder="选择开始时间" value-format="yyyy-MM-dd HH:mm:ss" default-time="00:00:00" /> </el-form-item> <el-form-item> <el-date-picker v-model="bannerQuery.end" type="datetime" placeholder="选择截止时间" value-format="yyyy-MM-dd HH:mm:ss" default-time="00:00:00" /> </el-form-item> <el-button type="primary" icon="el-icon-search" @click="getList()">查询</el-button> <el-button type="default" @click="resetData()">清空</el-button> </el-form> <!-- 轮播图列表 --> <el-table v-loading="listLoading" :data="bannerList" element-loading-text="数据加载中" border fit highlight-current-row> <el-table-column label="序号" width="125" align="center"> <template slot-scope="scope"> {{ (page - 1) * limit + scope.$index + 1 }} </template> </el-table-column> <el-table-column label="轮播图图片" width="500" align="center"> <template slot-scope="scope"> <div class="info"> <div class="pic"> <img :src="scope.row.imageUrl" alt="scope.row.title" width="300px"> </div> </div> </template> </el-table-column> <el-table-column prop="title" label="标题" width="130" align="center" /> <el-table-column prop="linkUrl" label="链接地址" width="80" align="center" /> <el-table-column prop="gmtCreate" label="添加时间" width="175" align="center" /> <el-table-column prop="sort" label="排序" width="80" align="center" /> <el-table-column label="操作" width="210" align="center"> <template slot-scope="scope"> <router-link :to="'/banner/edit/'+scope.row.id"> <el-button type="primary" size="mini" icon="el-icon-edit">修改</el-button> </router-link> <el-button type="danger" size="mini" icon="el-icon-delete" @click="removeDataById(scope.row.id)">删除</el-button> </template> </el-table-column> </el-table> <!-- 分页 --> <el-pagination background :current-page="page" :page-size="limit" :total="total" style="padding: 30px 0; text-align: center;" layout="total, prev, pager, next, jumper" @current-change="getList" /> </div> </template> <script> import banner from '@/api/edu/banner' export default { //注意不可以这样哦 Vue实例里面data可以写函数式或者对象式,但是组件里面只能写函数式!!! // data:{} data() {//定义变量和初始值 return { bannerList:null,//查询之后接口返回集合 page:1,//当前页 limit:2,//每页记录数 total:0,//总记录数 bannerQuery:{}//条件封装对象 } }, created() {//在页面渲染之前执行,一般调用methods中的方法 this.getList(); }, methods: {//创建具体的方法,调用teacher.js定义方法 //轮播列表的方法 getList(page = 1){//page默认值为1,当使用分页组件时会传入新的page参数 this.page = page banner.pageQuery(this.page,this.limit,this.bannerQuery) .then(response=>{ this.bannerList = response.data.items; console.log(response.data.total); this.total = response.data.total; }).catch(error=>{ console.log(error) }) }, //清空方法 resetData(){ //表单输入项情况 this.bannerQuery = {} //查询所有轮播列表数据 this.getList() }, //删除banner removeDataById(id){ this.$confirm('此操作将永久此轮播图记录,是否继续?','提示',{ confirmButtonText:'确定', cancelButtonText:'取消', type:'warning' }).then(()=>{//点击确定 banner.removeBanner(id).then((response)=>{ this.$message({ type:'success', message:'删除成功!' }) //回到列表页面 this.getList() }).catch(()=>{ this.$message({ type: 'error', message: '删除失败!' }) }) }).catch(() => { // 失败 this.$message({ type: 'info', message: '已取消删除!' }) }) } } } </script>
4、编写add.vue页面
<template> <div class="app-container"> <el-form label-width="120px"> <el-form-item label="标题"> <el-input v-model="banner.title"/> </el-form-item> <el-form-item label="排序"> <el-input-number v-model="banner.sort" controls-position="right" min="0"/> </el-form-item> <el-form-item label="链接地址"> <el-input v-model="banner.linkUrl"/> </el-form-item> <el-form-item label="轮播图片"> <el-upload :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" :action="BASE_API+'/ossService/file/upload'" class="avatar-uploader"> <img :src="banner.imageUrl"> </el-upload> </el-form-item> <el-form-item> <el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存</el-button> </el-form-item> </el-form> </div> </template> <style scoped> .tinymce-container { line-height: 29px; } </style> <script> import banner from '@/api/edu/banner' export default { data() { return { banner:{ imageUrl:'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cms/2019/11/14/297acd3b-b592-4cfb-a446-a28310369675.jpg', },//这里边写不写属性都可,因为程序会自动把页面绑定的属性添加进去 saveBtnDisabled: false, // 保存按钮是否禁用 BASE_API:process.env.BASE_API,//获取dev.env.js里面地址 } }, created() { this.init() }, watch:{//监听 $route(to,from){//当路由路径发生变化时,方法就会被执行 this.init() } }, methods: { //初始化 init(){ //判断路径中是否有id来决定是否进行回显功能 if(this.$route.params && this.$route.params.id){ //从路径中获取id值 const id = this.$route.params.id this.getBannerInfo(id)//进行回显 }else{ this.banner = { imageUrl:'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cms/2019/11/14/297acd3b-b592-4cfb-a446-a28310369675.jpg' } } }, saveOrUpdate(){ if(!this.banner.id){//通过判断id属性是否为空,来决定是添加还是修改 //添加 this.saveBanner(); }else{ this.updateBanner(); } this.saveBtnDisabled = true }, saveBanner(){ banner.addBanner(this.banner).then(response=>{ this.$message({ type:'success', message:'添加成功!' }); }).catch(error=>{ this.$message({ type:'error', message:'添加失败!' }); }) //回到列表页面,进行路由跳转 this.$router.push({path:'/banner/list'}) }, //根据id查询banner getBannerInfo(id){ banner.getById(id) .then(response=>{ this.banner = response.data.banner; }) }, // //修改banner updateBanner(){ banner.editBanner(this.banner) .then(response=>{ this.$message({ type:'success', message:'修改成功!' }); }).catch(error=>{ this.$message({ type:'error', message:'修改失败!' }); }) //回到列表页面,路由跳转 this.$router.push({path:'/banner/list'}) }, handleAvatarSuccess(res,file){//头像上传成功后 this.banner.imageUrl = res.data.url }, beforeAvatarUpload(file){//上传头像之前进行照片校验 const isPic = (file.type === 'image/jpeg' || file.type === 'image/jpg' || file.type === 'image/png') const isLt2M = file.size / 1024 / 1024 < 2 if (!isPic) { this.$message.error('上传头像图片只能是 JPG/JPEG/PNG 格式!') } if (!isLt2M) { this.$message.error('上传头像图片大小不能超过 2MB!') } return isPic && isLt2M } } } </script>
5、效果展示
三、首页显示banner数据 – 前台的前端
1、准备工作
(1)使用命令,下载axios依赖
npm install axios
(2)封装axios
项目下建立utils文件夹,里面新建request.js,用于对axios的封装.
import axios from 'axios' // 创建axios实例 const service = axios.create({ baseURL: 'http://localhost:9001', // api的base_url timeout: 20000 // 请求超时时间 }) export default service
2、首页banner 数据显示
(1)创建api 文件夹,在api文件夹创建banner.js文件,定义调用接口路径
import request from '@/utils/request' export default { //查询前两条banner数据 findAllBanner(){ return request({ url:`/cmsservice/bannerfront/findAllBanner`, method:'get' }) } }
(2)在index.vue页面调用接口得到数据进行显示
created() { //查询轮播图 this.getBannerList() }, methods: { //查询首页轮播图 getBannerList(){ banner.findAllBanner().then(response=>{ this.bannerList = response.data.data.bannerList }) } //... }
(3)修改轮播图展示页面
<!-- 幻灯片 开始 --> <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> <!-- 幻灯片 结束 -->
3、nginx进行访问规则配置




