新增套餐/redis/QuartZ
套餐其实就是检查组的集合,例如有一个套餐为“入职体检套餐”,这个体检套餐可以包括多个检查组:一般检查、血常规、尿常规、肝功三项等。所以在添加套餐时需要选择这个套餐包括的检查组。
套餐对应的实体类为Setmeal,对应的数据表为t_setmeal。套餐和检查组为多对多关系,所以需要中间表t_setmeal_checkgroup进行关联。
前端页面
弹出新增套餐页面功能
表单重置和默认选择tab项功能
动态列表显示检查组列表
在前端动态显示列表,就进行一个tableData的遍历即可,前端发送ajax请求到后台查询所有的记录并赋值给tableData,前端在对tableData进行处理
Controller
Service
ServiceImpl
Dao
Mapper
xml文件中的SQL语句,如果是查询所有数据,那么前端就不用传任何参数,只需发送一个get请求,sql语句中也不用写parameterType,只需要一个返回参数类型
<!-- 查询所有检查组--><select id="findAll" resultType="com.itheima.pojo.CheckGroup">select * from t_checkgroup</select>
parameterType="String" //查询是具有参数的,这个参数的类型是String
resultType="com.itheima.pojo.CheckGroup" //查询返回的参数类型
图片上传预览
此处使用的是ElementUI提供的上传组件el-upload,提供了多种不同的上传效果,上传成功后可以进行预览。
<!--
el-upload:上传组件
action:上传的提交地址
auto-upload:选中文件后是否自动上传
name:上传文件的名称,服务端可以根据名称获得上传的文件对象
show-file-list:是否显示已上传文件列表
on-success:文件上传成功时的钩子
before-upload:上传文件之前的钩子
-->
上传之前需要检验
//上传图片之前执行beforeAvatarUpload(file) {const isJPG = file.type === 'image/jpeg';const isLt2M = file.size / 1024 / 1024 < 2;if (!isJPG) {this.$message.error('上传套餐图片只能是 JPG 格式!');}if (!isLt2M) {this.$message.error('上传套餐图片大小不能超过 2MB!');}return isJPG && isLt2M;},
上传成功后,将图片的网络链接值赋给imageUr,imageUrll的值不为空,v-if条件成立,则显示图片的预览图
//文件上传成功后的钩子,response为服务端返回的值,file为当前上传的文件封装成的js对象handleAvatarSuccess(response, file) {this.imageUrl = 'http://rtb9a5bgc.hn-bkt.clouddn.com/' + response.data;this.$message({message: response.message,type: response.flag ? 'success' : 'error'});//设置模型数据(图片名称),后续提交ajax请求时会提交到后台最终保存到数据库this.formData.img = response.data;},
Controller
springmvc中需要设置一个文件上传的组件
<!--文件上传组件--><bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="maxUploadSize" value="104857600" /><property name="maxInMemorySize" value="4096" /><property name="defaultEncoding" value="UTF-8"/></bean>
之前设置的七牛云图片上传工具类中设置了两种图片上传方法,使用byte数组上传方法
//文件上传//图片上传@RequestMapping("/upload")public Result upload(@RequestParam("imgFile") MultipartFile imgFile){//使用springmvc的上传组件来上传文件,后台接收到文件System.out.println(imgFile);//获取原始文件名String originalFilename = imgFile.getOriginalFilename();int lastIndexOf = originalFilename.lastIndexOf(".");//获取文件后缀String suffix = originalFilename.substring(lastIndexOf - 1);//使用UUID随机产生文件名称,防止同名文件覆盖String fileName = UUID.randomUUID().toString() + suffix;try {QiniuUtils.upload2Qiniu(imgFile.getBytes(), fileName);//使用七牛云工具类的bytes数组上传文件方法,第二个参数为文件名//图片上传成功Result result = new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS);result.setData(fileName);return result;} catch (IOException e) {e.printStackTrace();//图片上传失败return new Result(false, MessageConstant.PIC_UPLOAD_FAIL);}}
完善新增套餐_提交表单
前端代码
//添加handleAdd () {//发送ajax请求,将表单数据(套餐信息,检查组ID)提交到后台进行处理axios.post("/setmeal/add.do?checkgroupIds=" + this.checkgroupIds,this.formData).then((res) =>{this.dialogFormVisible = false;if(res.data.flag){//本次操作成功,controller成功响应this.$message({message: res.data.message,type: 'success'});}else{this.$message.error(res.data.message);}}).finally(()=> {//本次操作失败this.findPage();});},
后台代码
完善图片上传
清理垃圾图片,释放磁盘空间
利用redis来保存图片名称,具体做法为:
1、当用户上传图片后,将图片名称保存到redis的一个Set集合中,例如集合名称为setmealPicResources
2、当用户添加套餐后,将图片名称保存到redis的另一个Set集合中,例如集合名称为setmealPicDbResources
3、计算setmealPicResources集合与setmealPicDbResources集合的差值,结果就是垃圾图片的名称集合,清理这些图片即可
配置好配置文件中,记得在springmvc.xml中引用
<import resource="spring-redis.xml"></import>
在health_common工程中提供Redis常量类
完善SetmealController,在文件上传成功后将图片名称保存到redis集合中
在health_service_provider项目中提供Spring配置文件applicationContext-redis.xml
查看是否能扫描到配置文件
完善SetmealServiceImpl服务类,在保存完成套餐信息后将图片名称存储到redis集合中
//将图片名称保存到RedissavePic2Redis(setmeal.getImg());
}
//将图片名称保存到Redis
private void savePic2Redis(String pic){jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES,pic);
}
定时任务组件Quartz
Quartz是Job scheduling(作业调度)领域的一个开源项目,Quartz既可以单独使用也可以跟spring框架整合使用,在实际开发中一般会使用后者。使用Quartz可以开发一个或者多个定时任务,每个定时任务可以单独指定执行的时间,例如每隔1小时执行一次、每个月第一天上午10点执行一次、每个月最后一天下午5点执行一次等。
pom文件中导入坐标
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>2.2.1</version></dependency></dependencies>
自定义一个job
提供Spring配置文件spring-jobs.xml,配置自定义Job、任务描述、触发器、调度工厂等
<!-- 注册自定义Job --><bean id="jobDemo" class="com.itheima.jobs.JobDemo"></bean><!-- 注册JobDetail,作用是负责通过反射调用指定的Job --><bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"><!-- 注入目标对象 --><property name="targetObject" ref="jobDemo"/><!-- 注入目标方法 --><property name="targetMethod" value="run"/></bean><!-- 注册一个触发器,指定任务触发的时间 --><bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"><!-- 注入JobDetail --><property name="jobDetail" ref="jobDetail"/><!-- 指定触发的时间,基于Cron表达式 --><property name="cronExpression"><value>0/10 * * * * ?</value></property></bean><!-- 注册一个统一的调度工厂,通过这个调度工厂调度任务 --><bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><!-- 注入多个触发器 --><property name="triggers"><list><ref bean="myTrigger"/></list></property></bean>
编写一个main方法来测试
Cron表达式
cron表达式分为七个域,之间使用空格分隔。其中最后一个域(年)可以为空。每个域都有自己允许的值和一些特殊字符构成。使用这些特殊字符可以使我们定义的表达式更加灵活。
下面是对这些特殊字符的介绍:
逗号(,):指定一个值列表,例如使用在月域上1,4,5,7表示1月、4月、5月和7月
横杠(-):指定一个范围,例如在时域上3-6表示3点到6点(即3点、4点、5点、6点)
星号(*):表示这个域上包含所有合法的值。例如,在月份域上使用星号意味着每个月都会触发
斜线(/):表示递增,例如使用在秒域上0/15表示每15秒
问号(?):只能用在日和周域上,但是不能在这两个域上同时使用。表示不指定
井号(#):只能使用在周域上,用于指定月份中的第几周的哪一天,例如6#3,意思是某月的第三个周五 (6=星期五,3意味着月份中的第三周)
L:某域上允许的最后一个值。只能使用在日和周域上。当用在日域上,表示的是在月域上指定的月份的最后一天。用于周域上时,表示周的最后一天,就是星期六
W:W 字符代表着工作日 (星期一到星期五),只能用在日域上,它用来指定离指定日的最近的一个工作日
cron表达式在线生成器
在线Cron表达式生成器
利用Quartz实现定时清理垃圾图片
创建maven工程health_jobs,打包方式为war,导入Quartz等相关坐标
导入坐标
配置web.xml
配置log4j.properties
配置applicationContext-redis.xml
配置applicationContext-jobs.xml
创建ClearImgJob定时任务类
套餐分页查询
定义分页相关的模型数据
pagination: {//分页相关模型数据currentPage: 1,//当前页码pageSize:10,//每页显示的记录数total:0,//总记录数queryString:null//查询条件
},
dataList: [],//当前页要展示的分页列表数据
findPage方法
//分页查询
findPage() {//分页参数var param = {currentPage:this.pagination.currentPage,//页码pageSize:this.pagination.pageSize,//每页显示的记录数queryString:this.pagination.queryString//查询条件};//请求后台axios.post("/setmeal/findPage.do",param).then((response)=> {//为模型数据赋值,基于VUE的双向绑定展示到页面this.dataList = response.data.rows;this.pagination.total = response.data.total;});
}
时机:钩子函数,查询按钮,分页条组件
后端开发同检查组后台开发