菜品模块 难度高
分析回顾
分页+文件上传+2张表查询
首先菜系同之前的菜系类似的有 增删改查 的功能.
区别是 加入了分页 功能
这里菜的编号 不是主键
添加功能: 文件上传 + 数据回显 (2表查询菜系+菜品)
菜系本身是一张表,用的就是主外键关联. 同时会员价格注意使用精度高的属性 double等是不合适的
分页代码
https://blog.csdn.net/qq_39088066/article/details/100061186
这一部分最关键的就是SQL语句了
将查询到的数据 进行分页 获取
整个数据被分割成 一块一块的
整个数据可以根据条件做减法来 获得满足要求的数据
public class FoodDao implements IFoodDao {
private QueryRunner qr = JdbcUtils.getQuerrRunner();
@Override
public Food findById(int id) {
try {
String sql = "SELECT * FROM food where id =?";
return qr.query(sql, new BeanHandler<Food>(Food.class), id);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public List<Food> findByType(int type) {
try {
// 根据食物类型找到食物
String sql = "SELECT * FROM food WHERE foodType_id =?";
return qr.query(sql, new BeanListHandler<Food>(Food.class), type);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public List<Food> query(String keyword) {
try {
String sql = "SELECT * FROM food WHERE foodName LIKE ?";
return qr.query(sql, new BeanListHandler<Food>(Food.class), "%" + keyword + "%");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public int getTotalCount(PageBean<Food> pb) {
// TODO Auto-generated method stub
//按条件查询PageBean.Condition
//因为s q l语句有大量相同的部分 所以使用字符串拼接的方法 节约代码String s = new String();[final类型定长 无法拼接]
StringBuilder sb = new StringBuilder();//分配地址绝对空 toString()变为String
sb.append("select count(*) from food f ,foodtype ft where f.foodType_id = ft.id ");
List<Object> list = new ArrayList<Object>();//存放sql 内? 的参数
//拿条件并分析
Condition condition = pb.getCondition();
if(condition!=null){
//按菜名查询
String foodName =condition.getFoodName();
if(foodName!=null&&!foodName.isEmpty()){//null ,new ,"" 情况都判断了
//String a = new String此时a是分配了内存空间,但值为空,是绝对的空,是一种有值(值存在为空而已)
//String b = ""此时b是分配了内存空间,值为空字符串,是相对的空,是一种有值(值存在为空字串)
//String c =null此时c是未分配内存空间,无值,是一种无值(值不存在
sb.append(" and f.foodName like ?");
list.add("%"+foodName+"%");
}
// 菜系
int type_id = condition.getFoodType_id();
if (type_id > 0) {
sb.append(" and f.foodType_id= ?");
list.add(type_id);
}
}
//sql凑完成 , ? 参数 编写完成
//最终我们要一个记录数
try {
Long count = qr.query(sb.toString(),new ScalarHandler<Long>(), list.toArray());//查询返回结果记录的第一行的第一列 (在聚合函数统计的时候用)
//集合转数组
return count.intValue(); //Long 转换为整型
} catch (SQLException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
}
}
//拿到分页后的每页的内容 没有返回值是因为返回内容传到PageBean类中了
@Override
public void getAll(PageBean<Food> pb) {
//1.拿到总记录数,并设置到PageBean
int totalCount = this.getTotalCount(pb);
pb.setTotalCount(totalCount);
// 控制翻页 首页 尾页 边界控制
if (pb.getCurrentPage() <= 0) {
pb.setCurrentPage(1);
} else if (pb.getCurrentPage() > pb.getTotalPage()) {
pb.setCurrentPage(pb.getTotalPage());
}
// 2.获取当前页:计算limit index,count
int currentPage = pb.getCurrentPage();
int index = (currentPage - 1) * pb.getPageCount();//起始
int count = pb.getPageCount();//返回行数
// 3.分页查询数据,按foodName和foodType_id
Condition condition = pb.getCondition();
StringBuilder sb = new StringBuilder();
sb.append("select f.id,f.foodName,f.foodType_id,f.price,f.mprice,f.remark,f.img,ft.typeName "
+ "from food f,foodtype ft " + " where f.foodType_id=ft.id");
// 存储查询条件的集合
List<Object> list = new ArrayList<Object>();
if (condition != null) {
String foodName = condition.getFoodName();
if (foodName != null && !foodName.isEmpty()) {
sb.append(" and f.foodName like ?");
list.add("%" + foodName + "%");
}
int type_id = condition.getFoodType_id();
if (type_id > 0) {
sb.append(" and f.foodType_id=?");
list.add(type_id);
}
}
sb.append(" limit ?,?");
list.add(index);
list.add(count);
try {
if (index >= 0) {
List<Food> pageData = qr.query(sb.toString(), new BeanListHandler<Food>(Food.class), list.toArray());
pb.setPageData(pageData);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
}
}
测试省略
下面开始业务层 业务层最有难度的就是 文件上传 和分页了
下面重点介绍一下
文件上传
// 添加菜 (之前已经拿到菜系内容)
private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
FileItemFactory factory = new DiskFileItemFactory(); //拿到工厂对象
ServletFileUpload upload = new ServletFileUpload(factory);//调用工具
upload.setFileSizeMax(10 * 1024 * 1024);
upload.setSizeMax(50 * 1024 * 1024);
upload.setHeaderEncoding("UTF-8");
if(upload.isMultipartContent(request)){
List<FileItem> list= upload.parseRequest(request);//拿到数据集合
Food food = new Food();
for(FileItem item : list){
//item---就是一条一条输入的内容
//是否文本
if(item.isFormField()){//法用于判断FileItem类对象封装的数据是一个普通文本表单字段,还是一个文件表单字段,
//如果是普通表单字段则返回true,否则返回false
String name=item.getFieldName(); //方法用于返回表单标签name属性的值:foodName
String value=item.getString(); //对象中保存的数据流内容以一个字符串返回:麻婆豆腐
value=new String(value.getBytes("ISO-8859-1"),"UTF-8");
BeanUtils.setProperty(food, name, value);
} else {
//文件
String fieldName=item.getFieldName();//img
String path = this.getServletContext().getRealPath("/upload");
File f=new File(path);
if(!f.exists()){
f.mkdirs();
}
String name=item.getName();//获得文件上传字段中的文件名
BeanUtils.setProperty(food, fieldName, "upload/"+name);
File file=new File(path,name);
if(!file.isDirectory()){//是否是目录
item.write(file);//write方法用于将FileItem对象中保存的主体内容保存到某个指定的文件中
}
item.delete();
//InputStream getInputStream() 以流的形式返回上传文件的数据内容。
// isInMemory方法用来判断FileItem对象封装的数据内容是存储在内存中,还是存储在临时文件中,
//如果存储在内存中则返回true,否则返回false。
}
}
foodService.add(food);
list(request,response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//dao
@Override
public void add(Food food) {
String sql = " INSERT food(foodName,foodType_id,price,mprice,remark,img) VALUES(?,?,?,?,?,?)";
try {
qr.update(sql,
food.getFoodName(),
food.getFoodType_id(),
food.getPrice(),
food.getMprice(),
ood.getRemark(),
food.getImg());//照片
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 分页显示全部内容
private void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String currPage = request.getParameter("currentPage");//前台传来的当前页
if (currPage == null || "".equals(currPage.trim())) {
currPage = "1";
}
int currentPage = Integer.parseInt(currPage);
PageBean<Food> pageBean = new PageBean<Food>();//拿到分页工具类
pageBean.setCurrentPage(currentPage);
foodService.getAll(pageBean);//拿到第一页的所有内容 5条存在了pageBean对象
List<Food> list = pageBean.getPageData(); // 拿出food数据
List<FoodType> types = new ArrayList<FoodType>(); // foodtype
if (list != null) {
for (Food food : list) {
FoodType foodtype = foodTypeService.findById(food.getFoodType_id());//外键起作用 拿到对应的内容
types.add(foodtype);
}
}
request.setAttribute("list", list);
request.setAttribute("types", types);
request.setAttribute("pageBean", pageBean);
uri = request.getRequestDispatcher("/sys/food/foodList.jsp");
goTo(request, response, uri);
}
// 统一跳转 优化 避免了重复写代码的尴尬
```javascript
private void goTo(HttpServletRequest request, HttpServletResponse response, Object uri)
throws ServletException, IOException {
if (uri instanceof RequestDispatcher){
((RequestDispatcher) uri).forward(request, response);
} else {
response.sendRedirect(request.getContextPath()+(String) uri);
} }