day18_查询功能 合并servlet

day18_查询功能 合并servlet

1.sql分析

-- 分页+条件 查询
select am1.*,IFNULL(am2.menuname,'无')  as pname from admin_menu am1 left join  admin_menu am2 on am1.pid = am2.mid

-- 动态查询条件 
where am1.menuname like CONCAT('%','理','%')
  and am1.pid = 13
-- page 当前页  pageSize 每页多少条 (page-1)*pageSize ,pageSize

limit 0,10



-- 总记录数 (查询条件需要与分段查询的保持一致 保持数据一致性)
select count(0) from admin_menu am1
where am1.menuname like CONCAT('%','理','%')
  and am1.pid = 13

注意点:

-- 1.查询语句需要考虑到关联数据的易用性 (提高用户体验)
-- 2.分页+条件 查询
-- 3.分页组件或者功能 经常需要总记录数total 通过total+pageSize  算总记录数

-- 算总页数  是否能整除 能整除直接整除 
--           有余数     除完加一页

总页数计算公式

    @Test
    public void myTest(){
        /*
        *   -- totalpage 总页数
            -- total     总记录数
            -- pageSize  每页多少条
        * */
        Integer total = 35;
        Integer pageSize = 7;
        Integer totalPage = total%pageSize==0?total/pageSize:total/pageSize+1;
        System.out.println(totalPage);


    }

2.查询功能dao和测试

两个查询方法 分段记录 和统计总记录数

//查询分段记录 (带limit)
List<AdminMenu> listMenuByCondition(@Param("inputMenu") AdminMenu inputMenu,@Param("startIdx")Integer startIdx,@Param("pageSize")Integer pageSize);

       <select id="listMenuByCondition" resultMap="AdminMenuBaseMap">
        select am1.*,IFNULL(am2.menuname,'无')  as pname from admin_menu am1 left join  admin_menu am2 on am1.pid = am2.mid
            <where>
                <if test="inputMenu.menuname != null and inputMenu.menuname !=''">
                    am1.menuname like CONCAT('%',#{inputMenu.menuname},'%')
                </if>
                <if test="inputMenu.pid != null ">
                    and am1.pid = #{inputMenu.pid}
                </if>
            </where>
            limit #{startIdx},#{pageSize}
    </select>


 //统计总记录数
 Integer countMenuByCondition(@Param("inputMenu") AdminMenu inputMenu);

    <select id="countMenuByCondition" resultType="java.lang.Integer">
        select count(0) from admin_menu am1
        <where>
            <if test="inputMenu.menuname != null and inputMenu.menuname !=''">
                am1.menuname like CONCAT('%',#{inputMenu.menuname},'%')
            </if>
            <if test="inputMenu.pid != null ">
                and am1.pid = #{inputMenu.pid}
            </if>
        </where>
    </select>

注意:

查询时 保持查询条件一致

附加知识(了解):

java实体对象使用过程中 基础用法使用一个实体对象

为了体现模式化 可能会出现同一个实体类建立多个实体对象的情况

image-20250818102642802

image-20250818102704111

image-20250818102716846

image-20250818102728416

image-20250818102759933

3查询接口

先考虑对接的数据

传入数据      menuname  		   菜单名称
			 pid                 上级编号
			 page                当前第几页    必填项  设定默认值 可以变成非必填项
 			 pageSize            每页多少条    必填项  设定默认值 可以变成非必填项

传出数据     json
package com.javasm.controller;

import com.alibaba.fastjson.JSON;
import com.javasm.entity.AdminMenu;
import com.javasm.entity.PageInfo;
import com.javasm.entity.Result;
import com.javasm.entity.ReturnCode;
import com.javasm.service.AdminMenuService;
import com.javasm.service.impl.AdminMenuServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * @className: MenuServlet
 * @description:
 * @author: gfs
 * @date: 2025/8/18 10:40
 * @version: 0.1
 * @since: jdk17
 */
@WebServlet("/menus")
public class MenuServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //允许跨域访问暂时写在公共⽗类中
        // /* 允许跨域的主机地址*/
        resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
        /* 允许跨域的请求⽅法GET, POST, HEAD 等*/
        resp.setHeader("Access-Control-Allow-Methods", "*");
        /* 重新预检验跨域的缓存时间(s) */
        resp.setHeader("Access-Control-Max-Age", "3600");
        /* 允许跨域的请求头*/
        resp.setHeader("Access-Control-Allow-Headers", "*");
        /* 是否携带cookie */
        resp.setHeader("Access-Control-Allow-Credentials", "true");


        //1接参数 封对象
        //页码参数
        String pageStr = req.getParameter("page");
        String pageSizeStr = req.getParameter("pageSize");
        //把page pageSize 做成非必填项  有默认值
        Integer page = 1;
        if(pageStr!=null&&!"".equals(pageStr)){
            page = Integer.valueOf(pageStr);
        }
        Integer pageSize = 10;
        if(pageSizeStr!=null&&!"".equals(pageSizeStr)){
            pageSize = Integer.valueOf(pageSizeStr);
        }
        //查询参数
        String menuname = req.getParameter("menuname");
        String pidStr = req.getParameter("pid");
        Long pid = null;
        if(pidStr!=null&&!"".equals(pidStr)){
            pid = Long.valueOf(pidStr);
        }
        AdminMenu inputMenu = new AdminMenu(menuname, pid);

        //2调用service
        AdminMenuService adminMenuService = new AdminMenuServiceImpl();
        Integer total = adminMenuService.countMenuByCondition(inputMenu);
        List<AdminMenu> adminMenus = adminMenuService.listMenuByCondition(inputMenu, page, pageSize);

        //3根据执行结果返回数据
        Result result = new Result();
        if(adminMenus.size()>0){
            result.setCode(ReturnCode.QUERY_SUCCESS.getCode());
            result.setMsg(ReturnCode.QUERY_SUCCESS.getMsg());
            //给table 菜单列表        adminMenus
            //给分页组件 页面信息对象   pageInfo
            PageInfo pageInfo = new PageInfo(page,pageSize,total);
            result.setPageInfo(pageInfo);
            result.setReturnData(adminMenus);
        }else{
            result.setCode(ReturnCode.QUERY_NODATA.getCode());
            result.setMsg(ReturnCode.QUERY_NODATA.getMsg());
        }

        resp.setContentType("application/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.print(JSON.toJSONString(result));
        writer.close();





    }
}

注意:

查询分段记录的service中 要把page转成startIdx

    @Override
    public List<AdminMenu> listMenuByCondition(AdminMenu inputMenu, Integer page, Integer pageSize) {
        SqlSession sqlSession = MyBatisHealper.getSqlSession();
        AdminMenuDao mapper = sqlSession.getMapper(AdminMenuDao.class);
		//把page 转成limit语句 需要的 起始索引  (page-1)*pageSize
        List<AdminMenu> adminMenus = mapper.listMenuByCondition(inputMenu,(page-1)*pageSize,pageSize);

        MyBatisHealper.backAndSaveSqlSession(sqlSession);
        return adminMenus;
    }

    @Override
    public Integer countMenuByCondition(AdminMenu inputMenu) {
        SqlSession sqlSession = MyBatisHealper.getSqlSession();
        AdminMenuDao mapper = sqlSession.getMapper(AdminMenuDao.class);
        Integer total = mapper.countMenuByCondition(inputMenu);

        MyBatisHealper.backAndSaveSqlSession(sqlSession);
        return total;
    }

4查询页面

联调和测试流程

从简单到完整功能

1.先把table数据对接上

2.美化调整table

3.加入分页组件 控制table数据重新查询

4.加入条件查询

5.测试数据和修复bug

注意 :

json对象组合语法

    let josn1 = {name:'jack',age:15};
    let json2 = {page:1,pageSize:10};

    console.log(josn1);
    console.log(json2);

    console.log({...josn1,...json2});

查询页面

<template>

<el-form ref="queryFormRef" :model="queryForm" :inline="true"  >
    <el-form-item label="菜单名称" prop="menuname">
      <el-input v-model="queryForm.menuname" style="width: 240px;"  placeholder="Approved by" clearable />
    </el-form-item>
    <el-form-item label="上级菜单" prop="pid">
      <el-select
        v-model="queryForm.pid"
        placeholder="请选择"
        style="width: 240px;"
        clearable
      >
        <!-- 1.写死数据 -->
        <!-- 2.动态加载  配一个菜单数据接口 -->
        <el-option label="无" value="0" />
        <el-option v-for="option in menuList" :label="option.menuname" :value="option.mid" />
      </el-select>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="querySubmit">查询</el-button>
      <el-button  @click="queryReset">重置</el-button>
    </el-form-item>
  </el-form>


    <el-table height="500" :data="tableData.dataList" style="width: 100%">
        <el-table-column prop="mid" label="菜单编号" width="80" />
        <el-table-column prop="menuname" label="菜单名称"/>
        <el-table-column prop="pid" label="上级编号" >
            <!--  通过自定义列信息 美化页面  scope.row 当前行的所有数据   -->
            <template #default="scope">
                <el-tag v-if="scope.row.pid == 0" type="success">
                    {{ scope.row.pid }}
                </el-tag>
                <el-tag v-else type="warning">
                    {{ scope.row.pid }}
                </el-tag>
            </template>
        </el-table-column>
        <el-table-column prop="pname" label="上级名称" >
            <template #default="scope">
                <el-tag v-if="scope.row.pid == 0" type="success">
                    {{ scope.row.pname }}
                </el-tag>
                <el-tag v-else type="warning">
                    {{ scope.row.pname }}
                </el-tag>
            </template>
        </el-table-column>
        <el-table-column prop="url" label="访问地址" />
        <el-table-column prop="glyphicon" label="图标" >
            <template #default="scope">
                <el-tag type="primary">
                    <el-icon> <component :is="scope.row.glyphicon"></component> </el-icon> 

                </el-tag>
                <el-tag type="primary">
                    {{ scope.row.glyphicon }}

                </el-tag>
                
            </template>


        </el-table-column>
    </el-table>

    <el-pagination
      v-model:current-page="tableData.pageInfo.page"
      v-model:page-size="tableData.pageInfo.pageSize"
      :total="tableData.pageInfo.total"
      :page-sizes="[10, 20, 30]"
      layout="total, sizes, prev, pager, next, jumper"
      @current-change="handlePageChange"
      @size-change="handleSizeChange"
      
    />



</template>

<script setup>
import { ref,reactive,onMounted } from 'vue'
import {Check,Delete,Edit,Message,Search,Star,Share} from '@element-plus/icons-vue'
import {myGet,myPost} from '@/myaxios'
//如果有后端数据 需要覆盖 为了保持响应时对象 需要这样建立
//table数据     dataList 
//页码信息数据   pageInfo
const tableData = reactive({dataList:[],
                            pageInfo:{    
                                    page:4,
                                    pageSize:20,
                                    total:78
                                }
})
//查询表单
const queryForm = reactive({
    menuname:'',
    pid:''
})

//查询表单对象
const queryFormRef = ref()

//查询表单 下拉列表数据
const menuList = ref([])


//提交查询
const querySubmit = ()=>{
    let params = queryForm;
    //发送请求
    myQuery(params)

}
//重置查询
const queryReset = ()=>{
    queryFormRef.value.resetFields()
    //重新查询数据
    myQuery({})
}

//page改变
const handlePageChange = (currentPage)=>{


    

    console.log(currentPage);
    //修改page页面参数
    tableData.pageInfo.page = currentPage;
    //把改后的page 作为参数 通过请求传走
    let params1 = tableData.pageInfo;
    let params2 = queryForm;
    //json对象组合语法
    let allParam = {...params1,...params2}

    //发送请求
    myQuery(allParam)
}
//pageSiez改变
const handleSizeChange = (currentPageSize)=>{
    //修改page页面参数
    tableData.pageInfo.page = 1;
    tableData.pageInfo.pageSize = currentPageSize;

    //把改后的page 作为参数 通过请求传走
    let params1 = tableData.pageInfo;
    let params2 = queryForm;
    //json对象组合语法
    let allParam = {...params1,...params2}
    //发送请求
    myQuery(allParam)

}

//查询公共方法
const myQuery = (params)=>{
    myGet("/menus",params)
    .then(resp=>{
        //多做日志输出     定位错误
        //打断点 分析错误  debugger
        console.log(resp.data);
        if(resp.data.code == 20000){
            tableData.dataList = resp.data.returnData
            tableData.pageInfo = resp.data.pageInfo
        }else if(resp.data.code == 20001){
            tableData.dataList = []
            tableData.pageInfo = {page:1,pageSize:10,total:0}
        }
    })
}
//查询一级菜单下拉列表
const queryMenuLevel1 = ()=>{
    myGet("/listMenuLevel1",{})
    .then(resp=>{
        menuList.value = resp.data.returnData
    })
}


onMounted(()=>{
    myQuery({})
    queryMenuLevel1()
})
</script>

<style scoped>

</style>

5合并servlet

image-20250818161139395

通过url体现执行的模块和方法

package com.javasm.controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @className: BaseServlet
 * @description:
 * @author: gfs
 * @date: 2025/8/18 16:04
 * @version: 0.1
 * @since: jdk17
 */
public class BaseServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
        * service方法中  自定请求分发规则
        *
        * 1.通过传参 + 自定义参数标记
        *   做方法分支
        *       String doWhat = req.getParameter("doWhat");
                if("query".equals(doWhat)){
                    this.listMenu(req,resp);
                }else if("listSelect".equals(doWhat)){
                    this.listMenuLevel1(req,resp);
                }
        * 2.rest风格   http协议规定的处理方式
        *   get      用于查询
        *   post     用于修改
        *   put      用于添加
        *   delete   用于删除
        *
        * 3.以url最后一段 写需要调用的方法名
        *   通过反射 做方法的通用调用方法 直接调用出入的方法名
        *
        * */

        //允许跨域访问暂时写在公共⽗类中
        // /* 允许跨域的主机地址*/
        resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
        /* 允许跨域的请求⽅法GET, POST, HEAD 等*/
        resp.setHeader("Access-Control-Allow-Methods", "*");
        /* 重新预检验跨域的缓存时间(s) */
        resp.setHeader("Access-Control-Max-Age", "3600");
        /* 允许跨域的请求头*/
        resp.setHeader("Access-Control-Allow-Headers", "*");
        /* 是否携带cookie */
        resp.setHeader("Access-Control-Allow-Credentials", "true");


        System.out.println("baseServlet.........");
        String methodName =  req.getRequestURI().substring(req.getRequestURI().lastIndexOf("/")+1);
        System.out.println(methodName);

        try {
            //根据方法名 获取方法对象
            Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            //可以获取到非public修饰符
            method.setAccessible(true);
            //调用方法
            method.invoke(this,req,resp);

        } catch (NoSuchMethodException e) {
            //throw new RuntimeException(e);
            resp.sendError(404,"loc error");
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }


    }


}

posted @ 2025-09-27 21:45  小胡coding  阅读(12)  评论(0)    收藏  举报