首语:上一篇已经初步介绍了定时任务,这次贴上一个demo小例的代码,内容主要就是模仿微信步数的刷新,后端技术利用Quartz调度框架,前端采用vue
要求:
1.用户输入账号、密码登录。
2.登录成功,在个人中心页面,显示用户基本信息。
3.在任务触发时间(如每晚10:06),刷新页面,可以看到当日步行排行榜。
4.适当准备好一些数据,便于展示。
用户类
@Entity
@Data
public class Sporter {
@Id
@GeneratedValue
private Integer id;
private String account;
private String avatar;
private String password;
private String bgpic;
/**
* 一对多关系,另一张表的外键
*/
@OneToMany(fetch = FetchType.EAGER , cascade = CascadeType.REMOVE)
@JoinColumn(name = "sporter_id")
private List<Walks> walksList = new ArrayList<>();
public Sporter() {
}
public Sporter(String account, String avatar, String password, String bgpic) {
this.account = account;
this.avatar = avatar;
this.password = password;
this.bgpic = bgpic;
}
public Sporter(String account, String avatar, String password, String bgpic, List<Walks> walksList) {
this.account = account;
this.avatar = avatar;
this.password = password;
this.bgpic = bgpic;
this.walksList = walksList;
}
}
步数类
@Data
@Entity
public class Walks {
@Id
@GeneratedValue
private Integer id;
/**
* 行走的步数
*/
private Integer walkCount;
/**
* 创建的时间
*/
private Date createTime;
public Walks() {
}
public Walks(Integer walkCount, Date createTime) {
this.walkCount = walkCount;
this.createTime = createTime;
}
public Integer getWalkCount() {
return walkCount;
}
public void setWalkCount(Integer walkCount) {
this.walkCount = walkCount;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
登陆dao
public interface LoginRepository extends JpaRepository<Sporter,Integer> {
Sporter findByAccountAndPassword(String account, String password);
Sporter findByAccount(String account);
}
步数dao
public interface WalksRepository extends JpaRepository<Walks,Integer> {
List<Walks>findAll();
}
登陆service
public interface LoginService {
Sporter findone(String account, String password);
Sporter getOne(String account);
/**
* 查找所有用户的信息,以及该用户下的步数信息
* @return
/
List<Sporter> getAll();
}
更新步数service
public interface WalksService {
/*
* 更新步数表中的数据
*/
void updateWalks();
}
登陆service实现类
@Service
public class LoginServiceImpl implements LoginService {
@Resource
private LoginRepository loginRepository;
@Override
public Sporter findone(String account, String password) {
return loginRepository.findByAccountAndPassword(account,password);
}
@Override
public Sporter getOne(String account) {
return loginRepository.findByAccount(account);
}
@Override
public List<Sporter> getAll() {
return loginRepository.findAll();
}
}
更新步数service实现类
@Service
public class WalksServiceImpl implements WalksService{
@Resource
private WalksRepository walksRepository;
@Override
public void updateWalks() {
List<Walks> list = walksRepository.findAll();
Random random = new Random();
for (int i=0;i<list.size();i++){
Walks walks = list.get(i);
System.out.println(walks);
walks.setWalkCount(random.nextInt(20000)+20000);
walks.setCreateTime(new Date());
walksRepository.saveAndFlush(walks);
}
}
}
用户登陆的controller层
@RestController
@CrossOrigin
@RequestMapping(value = "/st")
public class LoginController {
@Resource
private LoginService loginService;
@Resource
private WalksService walksService;
@GetMapping("/login")
public Sporter getuser(String account, String password){
return loginService.findone(account,password);
}
@GetMapping("/oneuser")
public Sporter getone(String account){
return loginService.getOne(account);
}
@GetMapping("/all")
public List<Sporter>getall(){
return loginService.getAll();
}
}
自定义job类
/**
-
自定义的Job任务类
*/
@Component
public class Jobs {
@Resource
private WalksService walksService;@Scheduled(cron = "0 36 0 * * ? ")
public void updateTodayWalks() throws Exception {
walksService.updateWalks();
}
}
/**
@author wn
-
quartz的配置类
*/
@Configuration
public class QuartzConfig {
@Autowired
private SpringJobFactory springJobFactory;@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setJobFactory(springJobFactory);
return schedulerFactoryBean;
}@Bean
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
}
/** @author wn
-
自定义的可配置的JobFactory
*/
@Component
public class SpringJobFactory extends AdaptableJobFactory {@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
/**
* 创建一个Job实列
* @param bundle
* @return
* @throws Exception
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
前端代码
主页
<template>
<div>
<div class="header">
<div class="collapse-btn" @click="collapseChage">
<i class="el-icon-menu"></i>
</div>
<div class="logo">定时任务</div>
<div class="header-right">
<div class="header-user-con">
<div class="btn-fullscreen" @click="handleFullScreen">
<el-tooltip effect="dark" :content="fullscreen?取消全屏
:全屏
" placement="bottom">
<i class="el-icon-rank"></i>
</el-tooltip>
</div>
<div class="user-avator"><img :src="responseUser.avatar"></div>
<el-dropdown class="user-name" trigger="click" @command="handleCommand">
<span class="el-dropdown-link">
{{username}} <i class="el-icon-caret-bottom"></i>
</span>
<el-dropdown-menu slot="dropdown">
<a href="#" target="_blank">
<el-dropdown-item>个人信息</el-dropdown-item>
</a>
<el-dropdown-item divided command="loginout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
<div>
<img :src="sporters[0].bgpic" style="height: 100px;width: 1400px"/>
</div>
<div class="container">
<div class="row" v-for="sporter in sporters " :key="sporter.id">
<div class="el-col-md-6">
<img class="card-img-center" :src="sporter.avatar"/>
<div class="card-body">
<p class="card-text">{{sporter.walksList[0].walkCount}}</p >
<p class="card-text">{{sporter.walksList[0].createTime}}</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import bus from '../components/common/bus';
export default {
data() {
return {
collapse: false,
fullscreen: false,
name: 'taoranran',
message: 2,
responseUser:[],
sporters:[]
}
},
computed:{
username(){
let username = localStorage.getItem('ms_username');
return username ? username : this.name;
}
},
created(){
var _this=this;
this.http.get('http://localhost:8080/st/all').then(function (res) {
_this.sporters=res.data
})
},
methods:{
// 用户名下拉菜单选择事件
handleCommand(command) {
if(command == 'loginout'){
localStorage.removeItem('ms_username')
this.$router.push('/');
}
},
// 侧边栏折叠
collapseChage(){
this.collapse = !this.collapse;
bus.$emit('collapse', this.collapse);
},
// 全屏事件
handleFullScreen(){
let element = document.documentElement;
if (this.fullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
} else {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.msRequestFullscreen) {
// IE11
element.msRequestFullscreen();
}
}
this.fullscreen = !this.fullscreen;
}
}
}
</script>
<style scoped>
.header {
position: relative;
box-sizing: border-box;
width: 100%;
height: 70px;
font-size: 22px;
color: #fff;
}
.collapse-btn{
float: left;
padding: 0 21px;
cursor: pointer;
line-height: 70px;
}
.header .logo{
float: left;
width:250px;
line-height: 70px;
}
.header-right{
float: right;
padding-right: 50px;
}
.header-user-con{
display: flex;
height: 70px;
align-items: center;
}
.btn-fullscreen{
transform: rotate(45deg);
margin-right: 5px;
font-size: 24px;
}
.user-name{
margin-left: 10px;
}
.user-avator{
margin-left: 20px;
}
.user-avator img{
display: block;
width:40px;
height:40px;
border-radius: 50%;
}
.el-dropdown-link{
color: #fff;
cursor: pointer;
}
</style>
登陆页
<template>
<div class="login-wrap">
<div class="ms-title">登 陆</div>
<div class="ms-login">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="0px" class="demo-ruleForm">
<el-form-item prop="username">
<el-input v-model="ruleForm.username" placeholder="username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" placeholder="password" v-model="ruleForm.password"></el-input>
</el-form-item>
<div class="login-btn">
<el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
</div>
</el-form>
</div>
</div>
</template>
<script>
export default {
data: function(){
return{
ruleForm: {
username: '',
password: ''
},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
]
}
}
},
methods: {
// login () {
// this.router.push('/home')
// })
// .catch(failResponse => {})
// },
submitForm(formName) {
this.http.get('http://localhost:8080/st/login?account='+this.ruleForm.username+'&password='+this.ruleForm.password)
.then(res => {
localStorage.setItem('ms_username',res.data.account);
if (res.data.account!=undefined){
this.alert("账号或密码错误!!!")
}
})
}else {
console.log('error submit!!');
return false;
}
});
}
}
}
</script>
<style scoped>
.login-wrap{
position: relative;
width:100%;
height:100%;
}
.ms-title{
position: absolute;
top:50%;
width:100%;
margin-top: -230px;
text-align: center;
font-size:30px;
color: #fff;
}
.ms-login{
position: absolute;
left:50%;
top:50%;
width:300px;
height:160px;
margin:-150px 0 0 -190px;
padding:40px;
border-radius: 5px;
background: #fff;
}
.login-btn{
text-align: center;
}
.login-btn button{
width:100%;
height:36px;
}
</style>
效果图