需求分析
2:前台代码
(1)弹出新增窗口 (2)动态展示跟团游列表 (3)图片上传并预览 ? 使用七牛云存储图片 (4)提交请求 ? 使用数据库存储图片名称 ? 使用springmvc的文件上传技术
3:后台代码
业务: ? 新增套餐 (1)SetmealController.java(Controller) (2)SetmealService.java(服务接口) (3)SetmealServiceImpl.java(服务实现类) (4)SetmealDao.java(Dao接口) (5)SetmealDao.xml(Mapper映射文件) 4:完善文件上传,Redis存储图片名称(一会说)
创建表
DROP TABLE IF EXISTS `t_setmeal`;
CREATE TABLE `t_setmeal` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(1000) DEFAULT NULL,
`code` varchar(8) DEFAULT NULL,
`helpCode` varchar(16) DEFAULT NULL,
`sex` char(1) DEFAULT NULL,
`age` varchar(32) DEFAULT NULL,
`price` float DEFAULT NULL,
`remark` varchar(3000) DEFAULT NULL,
`attention` varchar(128) DEFAULT NULL,
`img` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_setmeal_travelgroup`;
CREATE TABLE `t_setmeal_travelgroup` (
`setmeal_id` int(11) NOT NULL DEFAULT '0',
`travelgroup_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`setmeal_id`,`travelgroup_id`),
KEY `travelgroup_key` (`travelgroup_id`),
CONSTRAINT `travelgroup_key` FOREIGN KEY (`travelgroup_id`) REFERENCES `t_travelgroup` (`id`),
CONSTRAINT `setmeal_key` FOREIGN KEY (`setmeal_id`) REFERENCES `t_setmeal` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
需求分析
套餐其实就是跟团游的集合,例如有一个套餐为“北京深圳双飞套餐”,这个套餐可以包括多个跟团游。 所以在添加套餐时需要选择这个套餐包括的跟团游。 套餐对应的实体类为Setmeal,
public class Setmeal implements Serializable {
private Integer id;
private String name;
private String code;
private String helpCode;
private String sex;
private String age;
private Float price;
private String remark;
private String attention;
private String img;
private List<TravelGroup> travelGroups;
}
其中img字段表示套餐对应图片存储路径(用于存放七牛云上的图片名称) 对应的数据表为 t_setmeal。套餐和跟团游为多对多关系,所以需要中间表 t_setmeal_travelgroup 进行关联。
前台代码
套餐管理页面对应的是 setmeal.html 页面,根据产品设计的原型已经完成了页面基本结构的编写,现在需要完善页面动态效果
弹出新增窗口
页面中已经提供了新增窗口,只是出于隐藏状态。只需要将控制展示状态的属性 dialogFormVisible 改为true接口显示出新增窗口。点击新建按钮时绑定的方法为 handleCreate ,所以在 handleCreate 方法中修改dialogFormVisible 属性的值为true即可。同时为了增加用户体验度,需要每次点击新建按钮时清空表单输入项。 由于新增套餐时还需要选择此套餐包含的跟团游,所以新增套餐窗口分为两部分信息:基本信息和跟团游信息,如下图:
(1):新建按钮绑定单击事件,对应的处理函数为handleCreate
<el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
(2):handleCreate()方法:
resetForm() {
this.formData = {};
this.activeName='first';
this.travelgroupIds = [];
this.imageUrl = null;
},
handleCreate() {
this.dialogFormVisible = true;
this.resetForm();
},
动态展示跟团游列表
现在虽然已经完成了新增窗口的弹出,但是在跟团游信息标签页中需要动态展示所有的跟团游信息列表数据,并且可以进行勾选。具体操作步骤如下: (1)定义模型数据
tableData:[],//添加表单窗口中跟团游列表数据
travelgroupIds:[],//添加表单窗口中跟团游复选框对应id
(2)动态展示跟团游列表数据,数据来源于上面定义的tableData模型数据
<el-tab-pane label="跟团游信息" name="second">
<div class="checkScrol">
<table class="datatable">
<thead>
<tr>
<th>选择</th>
<th>项目编码</th>
<th>项目名称</th>
<th>项目说明</th>
</tr>
</thead>
<tbody>
<!--循环遍历tableData-->
<tr v-for="c in tableData">
<td>
<!--复选框绑定travelgroupIds,存放到值是id-->
<input :id="c.id" v-model="travelgroupIds" type="checkbox" :value="c.id">
</td>
<td><label :for="c.id">{{c.code}}</label></td>
<td><label :for="c.id">{{c.name}}</label></td>
<td><label :for="c.id">{{c.remark}}</label></td>
</tr>
</tbody>
</table>
</div>
</el-tab-pane>
其中:v-model=“travelgroupIds”,用于回显复选框。
(3)完善 handleCreate 方法,发送ajax请求查询所有跟团游数据并将结果赋值给tableData模型数据用于页面表格展示
// 弹出添加窗口
handleCreate() {
this.dialogFormVisible = true;
this.resetForm();
axios.get("/travelgroup/findAll.do").then((res)=> {
if(res.data.flag){
this.tableData = res.data.data;
}else{
this.$message.error(res.data.message);
}
});
},
(4)分别在 TravelGroupController 、TravelGroupService 、TravelGroupServiceImpl 、TravelGroupDao 、TravelGroupDao.xml 中扩展方法查询所有跟团游数据 1:TravelGroupController:
package com.atguigu.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.atguigu.constant.MessageConstant;
import com.atguigu.entity.PageResult;
import com.atguigu.entity.QueryPageBean;
import com.atguigu.entity.Result;
import com.atguigu.pojo.TravelGroup;
import com.atguigu.pojo.TravelItem;
import com.atguigu.service.TravelGroupService;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequestMapping("/travelgroup")
@RestController
public class TravelGroupController {
@Reference
private TravelGroupService travelGroupService;
//查询所有
@RequestMapping("/findAll")
public Result findAll(){
// 查询所有的跟团游
List<TravelGroup> travelGroupList = travelGroupService.findAll();
if(travelGroupList != null && travelGroupList.size() > 0){
//查询成功返回数据
Result result = new Result(true, MessageConstant.QUERY_SETMEAL_SUCCESS,travelGroupList);
return result;
}
return new Result(false,MessageConstant.QUERY_SETMEAL_FAIL);
}
2:TravelGroupService:
package com.atguigu.service;
import com.atguigu.entity.PageResult;
import com.atguigu.pojo.TravelGroup;
import com.atguigu.pojo.TravelItem;
import java.util.List;
public interface TravelGroupService {
List<TravelGroup> findAll();
3:TravelGroupServiceImpl:
package com.atguigu.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.atguigu.dao.TravelGroupDao;
import com.atguigu.entity.PageResult;
import com.atguigu.pojo.TravelGroup;
import com.atguigu.pojo.TravelItem;
import com.atguigu.service.TravelGroupService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service(interfaceClass = TravelGroupService.class)
@Transactional
public class TravelGroupServiceImpl implements TravelGroupService {
@Autowired
private TravelGroupDao travelGroupDao;
@Override
public List<TravelGroup> findAll() {
return travelGroupDao.findAll();
}
4:TravelGroupDao:
package com.atguigu.dao;
import com.atguigu.pojo.TravelGroup;
import com.atguigu.pojo.TravelItem;
import com.github.pagehelper.Page;
import java.util.List;
import java.util.Map;
public interface TravelGroupDao {
List<TravelGroup> findAll();
5:TravelGroupDao.xml:
<?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.atguigu.dao.TravelGroupDao">
<select id="findAll" resultType="travelGroup">
select * from t_travelgroup
</select>
</mapper>
图片上传并预览
此处使用的是ElementUI提供的上传组件el-upload,提供了多种不同的上传效果,上传成功后可以进行预览。 实现步骤: (1)定义模型数据,用于后面上传文件的图片预览:
imageUrl:null,//模型数据,用于上传图片完成后图片预览
(2)定义上传组件:
<!--
el-upload:上传组件
action:上传的提交地址(七牛云服务器)
auto-upload:选中文件后是否自动上传
name:上传文件的名称,服务端可以根据名称获得上传的文件对象
show-file-list:是否显示已上传文件列表
on-success:文件上传成功时的执行的钩子函数
before-upload:上传文件之前执行的钩子函数
-->
<el-upload
class="avatar-uploader"
action="/setmeal/upload.do"
:auto-upload="autoUpload"
name="imgFile"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<!--用于上传图片预览-->
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<!--用于展示上传图标-->
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
(3)定义对应的钩子函数:
// 注意axios执行url的时候,响应是通过response.data实现
// 注意elementUI执行url的时候,响应是通过response实现
//文件上传成功后的钩子,response为服务端返回的值,file为当前上传的文件封装成的js对象
handleAvatarSuccess(response, file) {
// 对imageUrl赋值,将图片显示到文件上传的框中,进行浏览
this.imageUrl = "http://q2t6dfukt.bkt.clouddn.com/"+response.data; // 用于显示
this.$message({
message: response.message,
type: response.flag ? 'success' : 'error'
});
//设置模型数据(图片名称),后续提交ajax请求时会提交到后台最终保存到数据库
this.formData.img = response.data; // 用于保存
},
//上传图片之前执行,const声明常量;var声明变量
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;
},
(4)创建SetmealController,接收上传的文件
package com.atguigu.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.atguigu.constant.MessageConstant;
import com.atguigu.entity.Result;
import com.atguigu.service.SetmealService;
import com.atguigu.utils.QiniuUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/setmeal")
public class SetmealController {
@Reference
private SetmealService setmealService;
// imgFile:需要跟页面el-upload里面的name保持一致
@RequestMapping("/upload")
//name="imgFile"是在el-upload标签中的imgFile 也可以用
public Result upload(MultipartFile imgFile) {
try {
//获取原始文件名
String originalFilename = imgFile.getOriginalFilename();
// 找到.最后出现的位置
int lastIndexOf = originalFilename.lastIndexOf(".");
//获取文件后缀
String suffix = originalFilename.substring(lastIndexOf);
//使用UUID随机产生文件名称,防止同名文件覆盖
String fileName = UUID.randomUUID().toString() + suffix;
QiniuUtils.upload2Qiniu(imgFile.getBytes(),fileName);
//图片上传成功 传回fileName用于回显那个图片上传成功
Result result = new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS, fileName);
return result;
} catch (IOException e) {
e.printStackTrace();
}
return new Result(false,MessageConstant.PIC_UPLOAD_FAIL);
}
}
!!!注意 :报错找不到http://localhost:82/setmeal/upload可能是 七牛的三个属性账号 密码 文件夹配置错了
String accessKey = "9_AiA8.....";
String secretKey = "Sem9.....";
String bucket = "shengdameinian";
注意:别忘了在spring配置文件中配置文件上传组件 已在springmvc.xml中配置
<!--文件上传组件-->
<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>
错误 解决方案
// Zone.zone2():表示华南,设置对应的地区
Configuration cfg = new Configuration(Zone.zone2());
提交请求
当用户点击新增窗口中的确定按钮时发送 ajax请求将数据提交到后台进行数据库操作。提交到后台的数据分为两部分:套餐基本信息(对应的模型数据为 formData)和跟团游 id数组(对应的模型数据为travelgroupIds)。 (1)为确定按钮绑定单击事件,对应的处理函数为handleAdd
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button>
<el-button type="primary" @click="handleAdd()">确定</el-button>
</div>
(2)完善handleAdd方法
//添加
handleAdd () {
axios.post("/setmeal/add.do?travelgroupIds=" + this.travelgroupIds,this.formData).then((response)=> {
this.dialogFormVisible = false;
if(response.data.flag){
this.$message({
message: response.data.message,
type: 'success'
});
}else{
this.$message.error(response.data.message);
}
}).finally(()=> {
this.findPage();
});
},
后台代码
Controller
在SetmealController中增加方法
package com.atguigu.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.atguigu.constant.MessageConstant;
import com.atguigu.entity.Result;
import com.atguigu.pojo.Setmeal;
import com.atguigu.service.SetmealService;
import com.atguigu.utils.QiniuUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/setmeal")
public class SetmealController {
@Reference
private SetmealService setmealService;
@RequestMapping("/add")
public Result add(@RequestBody Setmeal setmeal, Integer[] travelgroupIds){
try {
setmealService.add(setmeal,travelgroupIds);
}catch (Exception e){
return new Result(false,MessageConstant.ADD_SETMEAL_FAIL);
}
return new Result(true,MessageConstant.ADD_SETMEAL_SUCCESS);
}
服务接口
创建 SetmealService 接口并提供新增方法
package com.atguigu.service;
import com.atguigu.pojo.Setmeal;
public interface SetmealService {
public void add(Setmeal setmeal, Integer[] travelgroupIds);
}
服务实现类
创建 SetmealServiceImpl 服务实现类并实现新增方法
package com.atguigu.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.atguigu.dao.SetmealDao;
import com.atguigu.pojo.Setmeal;
import com.atguigu.service.SetmealService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
@Service(interfaceClass = SetmealService.class)
@Transactional
public class SetmealServiceImpl implements SetmealService {
@Autowired
private SetmealDao setmealDao;
@Override
public void add(Setmeal setmeal,Integer[] travelgroupId) {
setmealDao.add(setmeal);
if(travelgroupId != null && travelgroupId.length > 0){
setSetmealAndTravelGroup(setmeal.getId(),travelgroupId);
}
}
private void setSetmealAndTravelGroup(Integer id, Integer[] travelgroupId) {
for (Integer checkgroupId : travelgroupIds) {
Map<String,Integer> map = new HashMap<>();
map.put("checkgroup_id",checkgroupId);
map.put("setmeal_id",id);
setmealDao.setSetmealAndTravelGroup(map);
}
}
}
Dao接口
创建 SetmealDao 接口并提供相关方法
package com.atguigu.dao;
import com.atguigu.pojo.Setmeal;
import java.util.Map;
public interface SetmealDao {
void add(Setmeal setmeal);
void setSetmealAndTravelGroup(Map<String, Integer> map);
}
Mapper映射文件
创建 SetmealDao.xml 文件并定义相关SQL语句
<?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.atguigu.dao.SetmealDao">
<!--新增-->
<insert id="add" parameterType="setmeal">
<selectKey resultType="int" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
insert into t_setmeal(name,code,helpCode,sex,age,price,remark,attention,img) values (
</insert>
<!--绑定套餐和跟团游多对多关系-->
<insert id="setSetmealAndTravelGroup" parameterType="map">
insert into t_setmeal_travelgroup(setmeal_id,travelgroup_id) values (
</insert>
</mapper>
|