小帽学堂
8.课程支付总结
9. 课程详情页显示效果完善
// pages\course\_id.vue
< section v-if = " Number(courseWebVo.price) === 0" class = " c-attr-mt" >
< a @click = " createOrders()" title = " 立即观看" class = " comm-btn c-btn-3" > 立即观看</ a>
</ section>
< section v-else class = " c-attr-mt" >
< a @click = " createOrders()" title = " 立即购买" class = " comm-btn c-btn-3" > 立即购买</ a>
</ section>
二十五、统计分析模块需求
1. 需求描述
2. 生成统计数据接口
2.1 数据库
2.2 创建微服务
2.2.1 在service模块下创建子模块 service_statistics
2.2.2 application.properties
# 服务端口
server.port=8008
# 服务名
spring.application.name=service-statistics
# 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/atguigu/staservice/mapper/xml/*.xml
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#开启熔断机制
feign.hystrix.enabled=true
# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=
2.2.3 MP代码生成器生成代码
2.2.4 创建SpringBoot启动类
@SpringBootApplication
@ComponentScan ( basePackages = { "com.alex" } )
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan ( "com.alex.staservice.mapper" )
public class StaApplication {
public static void main ( String [ ] args) {
SpringApplication . run ( StaApplication . class , args) ;
}
}
2.3 实现服务调用
2.3.1 在service_ucenter模块创建接口,统计某一天的注册人数
@RestController
@RequestMapping ( "/educenter/member" )
@CrossOrigin
public class UcenterMemberController {
@Autowired
private UcenterMemberService memberService;
@GetMapping ( "countRegister/{day}" )
public R countRegister ( @PathVariable String day) {
Integer count = memberService. countRegisterDay ( day) ;
return R . ok ( ) . data ( "countRegister" , count) ;
}
}
public interface UcenterMemberService extends IService < UcenterMember > {
Integer countRegisterDay ( String day) ;
}
@Service
public class UcenterMemberServiceImpl extends ServiceImpl < UcenterMemberMapper , UcenterMember > implements UcenterMemberService {
@Override
public Integer countRegisterDay ( String day) {
return baseMapper. countRegisterDay ( day) ;
}
}
public interface UcenterMemberMapper extends BaseMapper < UcenterMember > {
Integer countRegisterDay ( String day) ;
}
<?xml version="1.0" encoding="UTF-8"?>
<! DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
< mapper namespace = " com.alex.educenter.mapper.UcenterMemberMapper" >
< select id = " countRegisterDay" resultType = " java.lang.Integer" >
SELECT COUNT(*) FROM ucenter_member uc
WHERE DATE(uc.gmt_create)=#{day}
</ select>
</ mapper>
2.3.2 在service_statistics模块创建远程调用接口
@Component
@FeignClient ( "service-ucenter" )
public interface UcenterClient {
@GetMapping ( "/educenter/member/countRegister/{day}" )
public R countRegister ( @PathVariable ( "day" ) String day) ;
}
2.3.3 在service_statistics模块调用微服务
@RestController
@RequestMapping ( "/staservice/sta" )
@CrossOrigin
public class StatisticsDailyController {
@Autowired
private StatisticsDailyService staService;
@PostMapping ( "registerCount/{day}" )
public R registerCount ( @PathVariable String day) {
staService. registerCount ( day) ;
return R . ok ( ) ;
}
}
public interface StatisticsDailyService extends IService < StatisticsDaily > {
void registerCount ( String day) ;
}
@Service
public class StatisticsDailyServiceImpl extends ServiceImpl < StatisticsDailyMapper , StatisticsDaily > implements StatisticsDailyService {
@Autowired
private UcenterClient ucenterClient;
@Override
public void registerCount ( String day) {
QueryWrapper < StatisticsDaily > wrapper = new QueryWrapper < > ( ) ;
wrapper. eq ( "date_calculated" , day) ;
baseMapper. delete ( wrapper) ;
R registerR = ucenterClient. countRegister ( day) ;
Integer countRegister = ( Integer ) registerR. getData ( ) . get ( "countRegister" ) ;
StatisticsDaily sta = new StatisticsDaily ( ) ;
sta. setRegisterNum ( countRegister) ;
sta. setDateCalculated ( day) ;
sta. setVideoViewNum ( RandomUtils . nextInt ( 100 , 200 ) ) ;
sta. setLoginNum ( RandomUtils . nextInt ( 100 , 200 ) ) ;
sta. setCourseNum ( RandomUtils . nextInt ( 100 , 200 ) ) ;
baseMapper. insert ( sta) ;
}
}
3. 生成统计数据前端整合
3.1 nginx配置
location ~ /staservice/ {
proxy_pass http://localhost:8008;
}
3.2 前端页面实现
import request from '@/utils/request'
export default {
createStaData ( day ) {
return request ( {
url : '/staservice/sta/registerCount/' + day,
method : 'post'
} )
}
}
{
path : '/sta' ,
component : Layout,
redirect : '/sta/create' ,
name : '统计分析' ,
meta : { title : '统计分析' , icon : 'example' } ,
children : [
{
path : 'create' ,
name : '生成数据' ,
component : ( ) => import ( '@/views/sta/create' ) ,
meta : { title : '生成数据' , icon : 'table' }
} ,
{
path : 'show' ,
name : '图表显示' ,
component : ( ) => import ( '@/views/sta/show' ) ,
meta : { title : '图表显示' , icon : 'tree' }
}
]
} ,
// src\views\sta\create.vue
< template>
< div class = " app-container" >
< el-form :inline = " true" class = " demo-form-inline" >
< el-form-item label = " 日期" >
< el-date-picker
v-model = " day"
type = " date"
placeholder = " 选择要统计的日期"
value-format = " yyyy-MM-dd" />
</ el-form-item>
< el-button
:disabled = " btnDisabled"
type = " primary"
@click = " create()" > 生成</ el-button>
</ el-form>
</ div>
</ template>
< script>
import sta from '@/api/sta'
export default {
data ( ) {
return {
day : '' ,
btnDisabled : false
}
} ,
created ( ) {
} ,
methods : {
create ( ) {
sta. createStaData ( this . day) . then ( response => {
this . btnDisabled = false
this . $message ( {
type : 'success' ,
message : '生成成功'
} )
this . $router. push ( { path : '/sta/show' } )
} )
}
}
}
</ script>
4. 整合定时任务
4.1 创建定时任务类,使用cron表达式
@Component
public class ScheduledTask {
@Autowired
private StatisticsDailyService statisticsDailyService;
@Scheduled ( cron = "0/5 * * * * ?" )
public void task1 ( ) {
System . out. println ( "******task1执行了*******" ) ;
}
@Scheduled ( cron = "0 0 1 * * ?" )
public void task2 ( ) {
statisticsDailyService. registerCount ( DateUtil . formatDate ( DateUtil . addDays ( new Date ( ) , - 1 ) ) ) ;
}
}
public class DateUtil {
private static final String dateFormat = "yyyy-MM-dd" ;
public static String formatDate ( Date date) {
SimpleDateFormat sdf = new SimpleDateFormat ( dateFormat) ;
return sdf. format ( date) ;
}
public static Date addDays ( Date date, int amount) {
Calendar now = Calendar . getInstance ( ) ;
now. setTime ( date) ;
now. set ( Calendar . DATE, now. get ( Calendar . DATE) + amount) ;
return now. getTime ( ) ;
}
public static void main ( String [ ] args) {
System . out. println ( DateUtil . formatDate ( new Date ( ) ) ) ;
System . out. println ( DateUtil . formatDate ( DateUtil . addDays ( new Date ( ) , - 1 ) ) ) ;
}
}
4.2 在启动类上添加注解
@EnableScheduling
public class StaApplication {
public static void main ( String [ ] args) {
SpringApplication . run ( StaApplication . class , args) ;
}
}
5. 图表显示(页面整合)
5.1 ECharts
5.1.1 简介
ECharts是百度的一个项目,后来百度把Echart捐给apache,用于图表展示,提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。
5.1.2 基本使用
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< meta http-equiv = " X-UA-Compatible" content = " IE=edge" >
< meta name = " viewport" content = " width=device-width, initial-scale=1.0" >
< title> 柱状图</ title>
< script src = " echarts.min.js" > </ script>
</ head>
< body>
< div id = " main" style = " width : 600px; height : 400px; " > </ div>
< script type = " text/javascript" >
var myChart = echarts. init ( document. getElementById ( 'main' ) ) ;
var option = {
title : {
text : 'ECharts Getting Started Example'
} ,
tooltip : { } ,
legend : {
data : [ 'sales' ]
} ,
xAxis : {
data : [ 'Shirts' , 'Cardigans' , 'Chiffons' , 'Pants' , 'Heels' , 'Socks' ]
} ,
yAxis : { } ,
series : [
{
name : 'sales' ,
type : 'bar' ,
data : [ 5 , 20 , 36 , 10 , 10 , 20 ]
}
]
} ;
myChart. setOption ( option) ;
</ script>
</ body>
</ html>
< script>
var myChart = echarts. init ( document. getElementById ( 'main' ) ) ;
var option = {
xAxis : {
type : 'category' ,
data : [ 'Mon' , 'Tue' , 'Wed' , 'Thu' , 'Fri' , 'Sat' , 'Sun' ]
} ,
yAxis : {
type : 'value'
} ,
series : [ {
data : [ 820 , 932 , 901 , 934 , 1290 , 1330 , 1320 ] ,
type : 'line'
} ]
} ;
myChart. setOption ( option) ;
</ script>
5.2 项目中集成ECharts
5.2.1 安装ECharts
npm install --save echarts@4.1.0
5.2.2 创建组件
// src\views\sta\show.vue
< template>
< div class = " app-container" >
< el-form :inline = " true" class = " demo-form-inline" >
< el-form-item>
< el-select v-model = " searchObj.type" clearable placeholder = " 请选择" >
< el-option label = " 学员登录数统计" value = " login_num" />
< el-option label = " 学员注册数统计" value = " register_num" />
< el-option label = " 课程播放数统计" value = " video_view_num" />
< el-option label = " 每日课程数统计" value = " course_num" />
</ el-select>
</ el-form-item>
< el-form-item>
< el-date-picker
v-model = " searchObj.begin"
type = " date"
placeholder = " 选择开始日期"
value-format = " yyyy-MM-dd" />
</ el-form-item>
< el-form-item>
< el-date-picker
v-model = " searchObj.end"
type = " date"
placeholder = " 选择截止日期"
value-format = " yyyy-MM-dd" />
</ el-form-item>
< el-button
:disabled = " btnDisabled"
type = " primary"
icon = " el-icon-search"
@click = " showChart()" > 查询</ el-button>
</ el-form>
< div class = " chart-container" >
< div id = " chart" class = " chart" style = " height : 500px; width : 100%" />
</ div>
</ div>
</ template>
< script>
import * as echarts from 'echarts' ;
export default {
data ( ) {
return {
searchObj : { } ,
btnDisabled : false
}
} ,
created ( ) {
} ,
methods : {
showChart ( ) {
this . chart = echarts. init ( document. getElementById ( 'chart' ) )
var option = {
xAxis : {
type : 'category' ,
data : [ 'Mon' , 'Tue' , 'Wed' , 'Thu' , 'Fri' , 'Sat' , 'Sun' ]
} ,
yAxis : {
type : 'value'
} ,
series : [ {
data : [ 820 , 932 , 901 , 934 , 1290 , 1330 , 1320 ] ,
type : 'line'
} ]
}
this . chart. setOption ( option)
}
}
}
</ script>
5.3 完成后端业务
@RestController
@RequestMapping ( "/staservice/sta" )
@CrossOrigin
public class StatisticsDailyController {
@Autowired
private StatisticsDailyService staService;
@GetMapping ( "showData/{type}/{begin}/{end}" )
public R showData ( @PathVariable String type, @PathVariable String begin, @PathVariable String end) {
Map < String , Object > map = staService. getShowData ( type, begin, end) ;
return R . ok ( ) . data ( map) ;
}
}
public interface StatisticsDailyService extends IService < StatisticsDaily > {
Map < String , Object > getShowData ( String type, String begin, String end) ;
}
@Service
public class StatisticsDailyServiceImpl extends ServiceImpl < StatisticsDailyMapper , StatisticsDaily > implements StatisticsDailyService {
@Override
public Map < String , Object > getShowData ( String type, String begin, String end) {
QueryWrapper < StatisticsDaily > wrapper = new QueryWrapper < > ( ) ;
wrapper. between ( "date_calculated" , begin, end) ;
wrapper. select ( "date_calculated" , type) ;
List < StatisticsDaily > staList = baseMapper. selectList ( wrapper) ;
List < String > date_calculatedList = new ArrayList < > ( ) ;
List < Integer > numDataList = new ArrayList < > ( ) ;
for ( int i = 0 ; i < staList. size ( ) ; i++ ) {
StatisticsDaily daily = staList. get ( i) ;
date_calculatedList. add ( daily. getDateCalculated ( ) ) ;
switch ( type) {
case "login_num" :
numDataList. add ( daily. getLoginNum ( ) ) ;
break ;
case "register_num" :
numDataList. add ( daily. getRegisterNum ( ) ) ;
break ;
case "video_view_num" :
numDataList. add ( daily. getVideoViewNum ( ) ) ;
break ;
case "course_num" :
numDataList. add ( daily. getCourseNum ( ) ) ;
default :
break ;
}
}
Map < String , Object > map = new HashMap < > ( ) ;
map. put ( "date_calculatedList" , date_calculatedList) ;
map. put ( "numDataList" , numDataList) ;
return map;
}
}
5.4 前后端整合
import request from '@/utils/request'
export default {
getDataSta ( searchObj ) {
return request ( {
url : ` /staservice/sta/showData/ ${ searchObj. type} / ${ searchObj. begin} / ${ searchObj. end} ` ,
method : 'get'
} )
}
}
// src\views\sta\show.vue
< template>
< div class = " app-container" >
< el-form :inline = " true" class = " demo-form-inline" >
< el-form-item>
< el-select v-model = " searchObj.type" clearable placeholder = " 请选择" >
< el-option label = " 学员登录数统计" value = " login_num" />
< el-option label = " 学员注册数统计" value = " register_num" />
< el-option label = " 课程播放数统计" value = " video_view_num" />
< el-option label = " 每日课程数统计" value = " course_num" />
</ el-select>
</ el-form-item>
< el-form-item>
< el-date-picker
v-model = " searchObj.begin"
type = " date"
placeholder = " 选择开始日期"
value-format = " yyyy-MM-dd" />
</ el-form-item>
< el-form-item>
< el-date-picker
v-model = " searchObj.end"
type = " date"
placeholder = " 选择截止日期"
value-format = " yyyy-MM-dd" />
</ el-form-item>
< el-button
:disabled = " btnDisabled"
type = " primary"
icon = " el-icon-search"
@click = " showChart()" > 查询</ el-button>
</ el-form>
< div class = " chart-container" >
< div id = " chart" class = " chart" style = " height : 500px; width : 100%" />
</ div>
</ div>
</ template>
< script>
import echarts from 'echarts' ;
import staApi from '@/api/sta'
export default {
data ( ) {
return {
searchObj : { } ,
btnDisabled : false ,
xData : [ ] ,
yData : [ ]
}
} ,
created ( ) {
} ,
methods : {
showChart ( ) {
staApi. getDataSta ( this . searchObj)
. then ( response => {
this . xData = response. data. date_calculatedList
this . yData = response. data. numDataList
this . setChart ( )
} )
} ,
setChart ( ) {
this . chart = echarts. init ( document. getElementById ( 'chart' ) )
var option = {
title : {
text : '数据统计'
} ,
tooltip : {
trigger : 'axis'
} ,
dataZoom : [ {
show : true ,
height : 30 ,
xAxisIndex : [
0
] ,
bottom : 30 ,
start : 10 ,
end : 80 ,
handleIcon : 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z' ,
handleSize : '110%' ,
handleStyle : {
color : '#d3dee5'
} ,
textStyle : {
color : '#fff'
} ,
borderColor : '#90979c'
} ,
{
type : 'inside' ,
show : true ,
height : 15 ,
start : 1 ,
end : 35
} ] ,
xAxis : {
type : 'category' ,
data : this . xData
} ,
yAxis : {
type : 'value'
} ,
series : [ {
data : this . yData,
type : 'line'
} ]
}
this . chart. setOption ( option)
}
}
}
</ script>