WEB综合案例

环境准备

先创建好web maven工程

搭建好mybatis的框架

(核心配置文件,pom依赖关系)

导入相关的数据库依赖,tomcat依赖还有封装好的sqlSessionFactoryUtils

还有我们写好的页面需要的

image-20220415184212718

准备好数据库

image-20220415184446240

查询所有

image-20220415184656957

在HTML中还要将数据设置到模型上,这样模型一变,显示就变了

DAO

/**
 * 查询所有
 * @return
 */
@Select("SELECT * FROM tb_brand")
@ResultMap("brandResultMap")
List<Brand> selectAll();

这里因为数据库中的列名和实体类中的名字不一样所以要用resultmap

image-20220415185034128

 
<mapper namespace="com.ember.mapper.BrandMapper">
    <resultMap id="brandResultMap" type="brand">
        <result column="brand_name" property="brandName"></result>
        <result column="company_name" property="companyName"></result>
    </resultMap>
</mapper>

service

这里和之前有点不一样,我们在service是通过写一个接口BrandService再写实现类来完成接口来写的,不像原来直接写成一个实现类(为了配合框架将service和web层解耦合)

image-20220415190809982

public interface BrandService {
    /*查询所有*/
    List<Brand> selectAll();
}
public class BrandServiceImpl implements BrandService {
    //.创建对应的sqlsessionfactory对象
    SqlSessionFactory factory= SqlSessionFactoryUtils.getSqlSessionFactory();

    @Override
    public List<Brand> selectAll() {
        //.获取sqlsession对象
        SqlSession sqlSession = factory.openSession();
        //.获取brandmapper
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        //.调用方法
        List<Brand> brands = mapper.selectAll();
        //.释放资源
        sqlSession.close();
        return brands;

    }
}

Web

因为要用到json

所以我们要导入依赖

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.62</version>
</dependency>
@WebServlet(name = "SelectAllServlet", value = "/selectAllServlet")
public class SelectAllServlet extends HttpServlet {
    private BrandService brandService=new BrandServiceImpl();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Brand> brands = brandService.selectAll();
        //.将集合转化为json,序列化数据
        String string = JSON.toJSONString(brands);
        //.响应数据,数据带中文所以要设置        response.setContentType("text/json;charset=utf-8");
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write(string);

    }

随后我们执行tomcat访问selectServlet可以看到数据返回说明成功了(我们小程序中使用的api'就是这个原理)

image-20220415191500450

前端代码

就是在页面中添加ajax(这里我们用的是axios所以要先导入axios.js文件)代码发送异步请求接收数据保存到data中

<script src="js/axios-0.18.0.js"></script>
mounted(){
//.当页面加载之后,发送异步请求获取数据
    var _this=this;
    axios({
        method:"get",
        url:"http://localhost:8080/cookie-demo/selectAllServlet"
    }).then(function (resp){
        _this.tableData= resp.data;
    })

}

访问页面,数据成功显示则成功

image-20220415192430762

新增品牌

三成结构代码大同小异

DAO

/*添加*/
@Insert("insert into tb_brand values(null,#{brandName},#{companyName},#{ordered},#{description},#{status})")
void add(Brand brand);

service

/*添加*/
void add(Brand brand);
@Override
public void add(Brand brand) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    mapper.add(brand);
    sqlSession.commit();
    sqlSession.close();
}

WEB

@WebServlet(name = "AddServlet", value = "/addServlet")
public class AddServlet extends HttpServlet {
    BrandService brandService=new BrandServiceImpl();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //.接收品牌数据
        BufferedReader reader = request.getReader();
        String params = reader.readLine();//.json字符串
        //.将字符串转为brand对象
        Brand brand = JSON.parseObject(params, Brand.class);
        //.调用service来添加
        brandService.add(brand);
        //.响应成功的标识
        response.getWriter().write("success");

    }

前端

找到对应的按钮对应的方法

image-20220415194114271

因为经常要刷新页面我们直接将相关代码写到一个方法里

//.查询所有的方法
selectAll(){
    var _this=this;
    axios({
        method:"get",
        url:"http://localhost:8080/cookie-demo/selectAllServlet"
    }).then(function (resp){
        _this.tableData= resp.data;
    })

}

那么原来写好的mounted就可以改成

mounted(){
//.当页面加载之后,发送异步请求获取数据
    this.selectAll();
 /*   var _this=this;
    axios({
        method:"get",
        url:"http://localhost:8080/cookie-demo/selectAllServlet"
    }).then(function (resp){
        _this.tableData= resp.data;
    })*/

}
addBrand() {
    var _this=this
   //.发送ajax请求,添加数据
    axios({
        method: "post",
        url: "http://localhost:8080/cookie-demo/addServlet",
        data:_this.brand
    }).then(function (resp){
        if(resp.data=="success"){
            //.添加成功
            //1.关闭窗口
        _this.dialogVisible = false;
        //2.重新查询数据
           _this.selectAll();
                              //3.弹出成功提示
                        _this.$message({
                            message: '恭喜你,添加成功',
                            type: 'success'
                        });
        }
    })
}

servlet代码优化

问题:WEB层的servlet个数太多了,不利于管理和编写

优化:

将servlet进行归类,对于同一个实体操作方法,写到一个servlet中。比如Brand实体对应BrandServlet,User->UserServlet

image-20220415201627365

我们现在就是要实现根据路径来实现方法分发,那么httpservlet这种根据请求方式实现方法分发的就不能用了

/*替换httpservlet的,根据请求的最后一段路径进行方法分发*/
public class BaseServlet extends HttpServlet {
    //.根据请求的最后一段路径进行方法分发
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //.获取请求路径
        String uri = req.getRequestURI();//   /cookie-demo/brand/selectAll
        //.获取最后一段路径(方法名)
        int index=uri.lastIndexOf("/");
        String methodName = uri.substring(index+1);
        //2.执行方法
        //2.1获取BrandServlet/UserServlet的字节码对象(class对象)
        Class<? extends BaseServlet> cls = this.getClass();
        //2.2获取方法 Method对象
        try {
            Method method= cls.getMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
            try {
                //.2.3执行方法
                method.invoke(this,req,resp);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }


    }
}
@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet{
    private BrandService brandService=new BrandServiceImpl();
    public void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Brand> brands = brandService.selectAll();
        //.将集合转化为json,序列化数据
        String string = JSON.toJSONString(brands);
        //.响应数据,数据带中文所以要设置        response.setContentType("text/json;charset=utf-8");
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().write(string);

    }
    public void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //.接收品牌数据
        BufferedReader reader = req.getReader();
        String params = reader.readLine();//.json字符串
        //.将字符串转为brand对象
        Brand brand = JSON.parseObject(params, Brand.class);
        //.调用service来添加
        brandService.add(brand);
        //.响应成功的标识
        resp.getWriter().write("success");
    }
}

再更改页面中的路径image-20220415204801109

image-20220415204812044

修改品牌信息

这里自己完成,我做的时候有几个难点

1.如何点击修改按钮获得当前行的id传给后端

2.如何实现表单中数据的回显

解决方法

1.参考了评论区

image-20220418111639441

实现代码

<el-table-column

        label="操作"
        align="center"
>
   <template slot-scope="scope">

        <el-button type="primary" @click="selectById(scope.$index,scope.row)"  >修改</el-button>

        <el-button type="danger" @click="deleteById(scope.$index,scope.row)" >删除</el-button>
   </template>
</el-table-column>

这里我是在data中创建了个对象用于存放后端查询后返回的数据

//修改行的数据
selectBrand:{},
selectById(index,row){

      var _this=this;
      console.log(row.id)
          this.update=true;
      axios({
          method:"get",
          url:"http://localhost:8080/cookie-demo/brand/selectById?id="+row.id


      }).then(function (resp){
          _this.selectBrand=resp.data;
          console.log(_this.selectBrand)
          //.显示修改对话框
          _this.update=true;

      })

  }

2.在对话框中设置回显,你看了上面对象你可能不知道为啥要新定义一个对象存数据(为了方便回显),应为vue是模型改变显示直接改变,所以当我们的输入框对应的模型中有数据时,输入框内就会显示出数据

下面给出代码

<!--修改对话框-->
    <el-dialog
            title="提示"
            :visible.sync="update"
            width="30%"
            :before-close="handleClose"
            :rules="rules">
        <el-form ref="form" :model="form" label-width="80px" >
            <el-form-item label="品牌名称" prop="brandName">
                <el-input v-model="selectBrand.brandName" ></el-input>
            </el-form-item>
            <el-form-item label="企业名称" prop="companyName">
                <el-input v-model="selectBrand.companyName"></el-input>
            </el-form-item>
            <el-form-item label="排序">
                <el-input v-model="selectBrand.ordered"></el-input>
                </el-select>
            </el-form-item>




            <el-form-item label="备注">
                <el-input type="textarea" v-model="selectBrand.description"></el-input>
            </el-form-item>
            <el-form-item label="状态">
                <el-switch v-model="selectBrand.status"
                           active-value="1"
                           inactive-value="0"></el-switch>
            </el-form-item>

            <el-form-item>
                <el-button type="primary" @click="updateBrand" >更新</el-button>
                <el-button @click="update=false">取消</el-button>
            </el-form-item>
        </el-form>
    </el-dialog>

效果展示

image-20220418112619032

DAO

        /*根据id查询*/
        @Select("SELECT * FROM tb_brand WHERE id=#{id}")
        @ResultMap("brandResultMap")
        Brand selectById(int id);

        /*修改数据*/
        @Update("UPDATE tb_brand " +
                "SET " +
                "brand_name=#{brandName}," +
                "company_name=#{companyName}, " +
                "ordered=#{ordered}," +
                "description=#{description}," +
                "status=#{status} WHERE id=#{id}")
        void update( Brand brand);

service

/*根据id查询*/
Brand selectById(int id);
void update(Brand brand);
@Override
public Brand selectById(int id) {
    //.获取sqlsession对象
    SqlSession sqlSession = factory.openSession();
    //.获取brandmapper
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    //.调用方法
    Brand brand = mapper.selectById(id);
    //.释放资源
    sqlSession.close();
    return brand;
}

@Override
public void update(Brand brand) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    mapper.update(brand);
    sqlSession.commit();
    sqlSession.close();
}

servlet

   public void selectById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        int id =Integer.parseInt(req.getQueryString());
        int id =Integer.parseInt(req.getParameter("id")) ;
        Brand brand=brandService.selectById(id);
        String string = JSON.toJSONString(brand);
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().write(string);

    }
    public void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //.接收品牌数据
        BufferedReader reader = req.getReader();
        String params = reader.readLine();//.json字符串
        //.将字符串转为brand对象
        Brand brand = JSON.parseObject(params, Brand.class);
        //.调用service来添加
        brandService.update(brand);
//        3.转发到查询所有的servlet
        resp.getWriter().write("success");
    }

删除和批量删除

DAO

mapper

/*删除数据*/
@Delete("DELETE  FROM tb_brand WHERE id=#{id}")
@ResultMap("brandResultMap")
void deleteById(int id);
/*批量删除要用动态sql所以不能使用注解,只能使用xml*/
void deleteByIds(@Param("ids") int[] ids);

service

service接口

/*删除*/
void deleteById(int id);
/*批量删除*/
void deleteByIds(int[] ids);

service实现类

@Override
public void deleteById(int id) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    mapper.deleteById(id);
    sqlSession.commit();
    sqlSession.close();
}

@Override
public void deleteByIds(int[] ids) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    mapper.deleteByIds(ids);
    sqlSession.commit();
    sqlSession.close();
}

servlet

public void deleteById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    int id =Integer.parseInt(req.getParameter("id")) ;
    brandService.deleteById(id);
    resp.getWriter().write("success");
}
/*批量删除*/
public void deleteByIds(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //.接收品牌数据
    BufferedReader reader = req.getReader();
    String params = reader.readLine();//.json字符串
    //.将字符串转为brand对象
    int[] ints = JSON.parseObject(params, int[].class);
    //.调用service来添加
    brandService.deleteByIds(ints);
    //.响应成功的标识
    resp.getWriter().write("success");
}

前端

绑定点击事件

image-20220419105434968

image-20220419105601390

在data中增加数组存放被选中的值

image-20220419105659924

方法实现

deleteById(index,row){
    var _this=this;
    this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
        axios({
            method:"get",
            url:"http://localhost:8080/cookie-demo/brand/deleteById?id="+row.id
            // data:"id="+_this.brand.id


        }).then(function (resp){
            if(resp.data=="success"){
                //.添加成功
                //1.关闭窗口
                _this.dialogFormVisible = false;
                //2.重新查询数据
                _this.selectAll();
                //3.弹出成功提示
                _this.$message({
                    message: '恭喜你,删除成功',
                    type: 'success'
                });
            }

        })
    }).catch(() => {
        this.$message({
            type: 'info',
            message: '已取消删除'
        });
    });

我们看复选框的代码可以发现每次选中就会将值存入一个数组中

image-20220419105850375

所以我们批量删除可以直接从这个数组中筛选每个值的id

image-20220419110003799

方法实现

deleteByIds(){
    //弹出确认的提示框

    this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
    //用户点确定按钮

        //1.创建id数组[1,2,3],从multipleSelection中获取即可
        // console.log(this.multipleSelection)
        for (let i = 0; i < this.multipleSelection.length; i++) {
            let selectionElement = this.multipleSelection[i];
            this.selectedIds[i]=selectionElement.id;
        }
        //2.发送ajax请求
        var _this=this
        //.发送ajax请求,添加数据
        axios({
            method: "post",
            url: "http://localhost:8080/cookie-demo/brand/deleteByIds",
            data:_this.selectedIds
        }).then(function (resp){
            if(resp.data=="success"){
                //.添加成功
                //1.关闭窗口
                _this.dialogVisible = false;
                //2.重新查询数据
                _this.selectAll();
                //3.弹出成功提示
                _this.$message({
                    message: '恭喜你,删除成功',
                    type: 'success'
                });
            }
        })
    }).catch(() => {
        this.$message({
            // 用户点击取消按钮
            type: 'info',
            message: '已取消删除'
        });
    })

}

分页查询

sql语句关键字limit

SELECT * FROM LIMIT 参数1,参数2

第一个参数是开始的开始的索引

第二个参数是查询的条目数

页面传递的参数

当前页码 i

每页显示的条数n

第一个参数=(i-1)*n

第二个参数=n

业务逻辑分析

image-20220419111419990

首先完成pagebean类

//.分页查询的JavaBean

import java.util.List;

public class PageBean<T> {
    //.总记录数
    private int totalCount;
    //.当前页的数据
    private List<T> rows;

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    public List<T> getRows() {
        return rows;
    }

    public void setRows(List<T> rows) {
        this.rows = rows;
    }
}

后端逻辑

DAO

/*分页查询*/
@Select("SELECT * FROM tb_brand LIMIT #{begin},#{size}")
List<Brand> selectByPage(@Param("begin")int begin,@Param("size")int size);
/*查询总记录数
* */
@Select("SELECT COUNT(*) FROM tb_brand")
int selectTotalCount();

service

/*分页
* @param currentPage 当前页码
* @param pageSize每页展示条数*/
PageBean<Brand> selectByPage(int currentPage,int pageSize);
@Override
public PageBean<Brand> selectByPage(int currentPage, int pageSize) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    //.计算开始索引

    int begin=(currentPage-1)*pageSize;
    //.查询的条目数
    int size=pageSize;
    //.查询当前页数据
    List<Brand> rows = mapper.selectByPage(begin, size);
    //.查询总条数
    int totalCount = mapper.selectTotalCount();
    //.封装pageBean对象
    PageBean<Brand> pageBean=new PageBean<>();
    pageBean.setRows(rows);
    pageBean.setTotalCount(totalCount);
    //.释放资源
    sqlSession.close();

    return pageBean;
}

servlet

/*分页查询*/
public void selectByPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //.从前端接收当前页码和每页展示条数 url?currentPage=1&pageSize=5
    String _currentPage = req.getParameter("currentPage");
    String _pageSize = req.getParameter("pageSize");
    int currentPage = Integer.parseInt(_currentPage);
    int pageSize = Integer.parseInt(_pageSize);
    PageBean<Brand> pageBean = brandService.selectByPage(currentPage, pageSize);


    //.将集合转化为json,序列化数据
    String string = JSON.toJSONString(pageBean);
    //.响应数据,数据带中文所以要设置        response.setContentType("text/json;charset=utf-8");
    resp.setContentType("text/json;charset=utf-8");
    resp.getWriter().write(string);

}

后来maven启动传入参数看是否能返回数据

image-20220419141415682

前端代码

增加两个变量用于动态改变当前页显示条数和总条数

image-20220419143649474

selectAll(){
var _this=this;
axios({
          method:"get",
          url:"http://localhost:8080/cookie-demo/brand/selectByPage?currentPage="+_this.currentPage+"&pageSize="+_this.pageSize+""
      }).then(function (resp){
    _this.tableData= resp.data.rows;
    _this.totalCount=resp.data.totalCount;
})
},

更改点击分页的代码

//分页
handleSizeChange(val) {
    // console.log(`每页 ${val} 条`);
    this.pageSize=val;
    this.selectAll();
},
handleCurrentChange(val) {
    // console.log(`当前页: ${val}`);
    this.currentPage=val;
    this.selectAll();
},

条件查询

要使用动态sql

image-20220419144043231

后端逻辑

image-20220419144401921

DAO

/*分页条件查询*/

List<Brand> selectByPageAndCondition(@Param("begin")int begin,@Param("size")int size,@Param("brand")Brand brand);


/*根据条件查询总记录数*/
int selectTotalCountByCondition(Brand brand);
<!--        WHERE brand_name=#{brand.brandName}-->
<select id="selectByPageAndCondition" resultMap="brandResultMap">
    SELECT *
    FROM tb_brand
    <where>
        <if test="brand.brandName!=null and brand.brandName!=''">
            and brand_name LIKE #{brand.brandName}
        </if>
        <if test="brand.companyName!=null and brand.companyName!=''">
            and company_name LIKE #{brand.companyName}
        </if>
        <if test="brand.status!=null ">
            and status=#{brand.status}
        </if>
    </where>
    LIMIT #{begin},#{size}
</select>
<select id="selectTotalCountByCondition" resultType="java.lang.Integer">
    SELECT COUNT(*)
    FROM tb_brand
    <where>
        <if test="brandName!=null and brandName!=''">
            and brand_name LIKE #{brandName}
        </if>
        <if test="companyName!=null and companyName!=''">
            and company_name LIKE #{companyName}
        </if>
        <if test="status!=null ">
            and status=#{status}
        </if>
    </where>
</select>

这里的难点就是sql语句的书写(动态sql)

SERVICE

重难点是对数据有模糊处理,这对sql基础有要求

/*分页条件查询
 * @param currentPage 当前页码
 * @param pageSize每页展示条数*/
PageBean<Brand> selectByPageAndCondition(int currentPage,int pageSize,Brand brand);
    @Override
    public PageBean<Brand> selectByPageAndCondition(int currentPage, int pageSize,Brand brand) {
        SqlSession sqlSession = factory.openSession();
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        //.计算开始索引

        int begin=(currentPage-1)*pageSize;
        //.查询的条目数
        int size=pageSize;
//        因为是模糊查询所以要处理下brand条件(在数据两边加上%)
        String brandName = brand.getBrandName();
        if(brandName!=null&& brandName.length()>0){
            brand.setBrandName("%"+brandName+"%");
        }
        String companyName = brand.getCompanyName();
        if(companyName!=null && companyName.length()>0){
            brand.setCompanyName("%"+companyName+"%");
        }

        //.查询当前页数据
        List<Brand> rows = mapper.selectByPageAndCondition(begin, size,brand);
        //.查询总条数
        int totalCount = mapper.selectTotalCountByCondition(brand);
        //.封装pageBean对象
        PageBean<Brand> pageBean=new PageBean<>();
        pageBean.setRows(rows);
        pageBean.setTotalCount(totalCount);
        //.释放资源
        sqlSession.close();

        return pageBean;
    }

selvlet

/*分页条件查询*/
public void selectByPageAndCondition(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //.从前端接收当前页码和每页展示条数 url?currentPage=1&pageSize=5
    String _currentPage = req.getParameter("currentPage");
    String _pageSize = req.getParameter("pageSize");
    int currentPage = Integer.parseInt(_currentPage);
    int pageSize = Integer.parseInt(_pageSize);
    //.获取查询条件对象
    BufferedReader br=req.getReader();
    String params = br.readLine();
    //转为Brand对象
    Brand brand = JSON.parseObject(params, Brand.class);

    PageBean<Brand> pageBean = brandService.selectByPageAndCondition(currentPage, pageSize,brand);


    //.将集合转化为json,序列化数据
    String string = JSON.toJSONString(pageBean);
    //.响应数据,数据带中文所以要设置        response.setContentType("text/json;charset=utf-8");
    resp.setContentType("text/json;charset=utf-8");
    resp.getWriter().write(string);

}

前端

image-20220419154934288

更改了seletAll代码

get->post

image-20220419155139094

并且传入了输入的brand对象

前端代码优化

主要是js中方法中使用this要用参数引用,这一点很不方便

var _this=this

我们可以使用箭头函数,比如下面我们的selectAll方法就可以改成

selectAll(){

axios({
          method:"post",
          url:"http://localhost:8080/cookie-demo/brand/selectByPageAndCondition?currentPage="+this.currentPage+"&pageSize="+this.pageSize,
          data:this.brand
}).then(resp=>{
    this.tableData= resp.data.rows;
    this.totalCount=resp.data.totalCount;
})
},
posted @ 2022-04-15 20:50  Ember00  阅读(143)  评论(0)    收藏  举报