JavaWeb、终章案例

目录

一、环境搭建

二、编写前端页面

三、连接后端代码实现具体功能

1、查询所有

        2、新增

        3、代码优化

1、 创建BaseServlet继承HttpServlet重写service方法

2、创建不同对象的Servlet将不同的Servlet封装成方法

        4、删除品牌

        如何获取页面id并将id传递给后端

        5、修改品牌

        数据回调传递到前端并展示

        前端页面返回给后端的JSON中文格式乱码问题

        后端返回给前端中文乱码问题

        6、批量删除

        获取前端页面复选框选中的id数组,传递给后端

        7、分页查询

        8、多条件分页查询

        多条件查询后还要通过分页查询展示数据


一、环境搭建

参照 Web案例

在pom.xml中再导入fastjson坐标

<!--导入fastjson坐标-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.62</version>
    </dependency>

二、编写前端页面

通过Element官网的代码编写基于Vue的前端页面

三、连接后端代码实现具体功能

1、查询所有

注意在Vue中使前后端信息交互使用axios异步请求实现

在Vue的data数据中创建数据模型,使后端的数据传递到前端模型中

data() {
            return {
                //当前页码
                currentPage: 1,
                //对话框默认为false隐藏
                dialogVisible: false,

                //品牌模型数据
                brand: {
                    status: '',
                    brandName: '',
                    companyName:'',
                    id:'',
                    ordered:'',
                    description:''
                },
                //表格数据模型
                tableData: [{
                    brandName: '三只松鼠',
                    companyName: '三只松鼠',
                    description: 'dsds',
                    ordered: '10',
                    status: '1',
                }],
                /*复选框选中的数据集合*/
                multipleSelection: []
            }
        }

再通过遍历将数据库中的结果展示

<!--表格数据-->
    <el-table
            :data="tableData"
            style="width: 100%"
            @Selection-change="handleSelectionChange"
            :row-class-name="tableRowClassName">
        <el-table-column
                type="selection"
                width="55">
        </el-table-column>
        <el-table-column
                type="index"
                width="50">
        </el-table-column>
        <el-table-column
                //对应模型中的名称
                prop="brandName"
                label="品牌名称"
                align="center">
        </el-table-column>
        <el-table-column
                prop="companyName"
                label="企业名称"
                align="center">
        </el-table-column>
        <el-table-column
                prop="description"
                label="企业描述"
                align="center">
        </el-table-column>
        <el-table-column
                prop="ordered"
                align="center"
                label="排序">
        </el-table-column>
        <el-table-column
                prop="status"
                align="center"
                label="当前状态">
        </el-table-column>
        <el-table-column
                align="center"
                label="操作">
            <!--标签内写按钮-->
            <el-row>
                <el-button type="primary">修改</el-button>

                <el-button type="danger">删除</el-button>
            </el-row>
        </el-table-column>
    </el-table>

前端页面向后端发送axios异步请求,使用Vue的生命周期mounted 使在页面加载完成后发送异步请求获取数据,将查询所有封装成方法,内部使用axios异步请求

mounted(){
            //页面加载完成后发送异步请求获取数据
            this.selectAll();
        },

        methods: {
            //查询所有数据
            selectAll(){
                var _this=this
                //页面加载完成后发送异步请求获取数据
                axios({
                          method:"get",
                          url:"http://localhost:8080/webcore_case_war/brand/selectAll"
                      }).then(function (resp){
                    //将后端数据传递给前端模型
                    _this.tableData = resp.data;
                })
            },

 这里需要注意:在axios中的this为undefined,他不能代表Vue中的数据,而Vue中的this始终指向Vue,所以要使用this做回调函数,需要在axios外部对this进行处理。

后端Servlet的逻辑

//通过service方法返回sql结果
        List<Brand> brandList = brandService.selectAll();

        //将返回的结果响应到页面
        //将List集合转换为JSON
        String brands = JSON.toJSONString(brandList);

        //将结果相应到页面
        resp.setContentType("text/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.write(brands);

 后端需要注意的是:在service层中要使用接口规范Brand对象的方法,然后再service下创建包impl存放实现类。

2、新增

前端代码

前端创建表单通过axios异步请求携带表单数据提交到后端进行处理

    <!--对话框-->
    <el-dialog
            title="添加品牌"
            :visible.sync="dialogVisible"
            width="30%"
            :before-close="handleClose">
        <!--内部加入表单-->
        <el-form ref="form" :model="brand" label-width="80px">
            <el-form-item label="品牌名称">
                <el-input v-model="brand.brandName"></el-input>
            </el-form-item>
            <el-form-item label="企业名称">
                <el-input v-model="brand.companyName"></el-input>
            </el-form-item>
            <el-form-item label="排序">
                <el-input v-model="brand.ordered"></el-input>
            </el-form-item>
            <el-form-item label="企业描述">
                <el-input type="textarea" v-model="brand.description"></el-input>
            </el-form-item>
            <el-form-item label="状态">
                <el-switch v-model="brand.status"
                            //按钮的switch逻辑,开启按钮表示status为1
                           active-value="1"
                           inactive-value="0">
                </el-switch>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="addBrand">立即创建</el-button>
                <el-button @click="dialogVisible = false">取消</el-button>
            </el-form-item>
        </el-form>

  </span>
    </el-dialog>

使用addBrand方法通过axios携带表单数据提交到后台数据库,再调用查询所有的方法

//提交新增数据
            addBrand() {
                var _this = this;
                //发送异步请求,携带表单数据
                axios({
                    method:"post",
                    url:"http://localhost:8080/webcore_case_war/brand/addBrand",
                    //携带表单数据
                    data:_this.brand
                }).then(function (resp){
                    //判断后端返回的是否是success字符串
                    if (resp.data == "success"){
                        //添加成功关闭窗口
                        _this.dialogVisible = false;

                        //再次查询数据
                        _this.selectAll();

                        //添加成功弹出消息
                        _this.$message({
                            message: '恭喜你,添加成功',
                            type: 'success'
                        })
                    }
                })
            },

后端逻辑

前端的JSON数据要使用流读取

//获取前端数据,前端数据是以JSON格式提交的,使用流读取
        BufferedReader reader = req.getReader();
        String s = reader.readLine(); //对应的JSON字符串
        //将对应的JSON字符串转为java对象
        Brand brand = JSON.parseObject(s, Brand.class);

        //将获取的数据封装到数据库
        brandService.addBrand(brand);

        //响应成功的标识
        resp.getWriter().write("success");

3、代码优化

由于每实现一个功能就要创建一个Servlet,会使得Servlet的文件越来越多,因此对后端Servlet进行代码优化

可以发现所有的Servlet都使用了doGet和doPost方法实现数据转发,而doGet、doPost是Servlet内部写好的方法,所以我们可以重写HttpServlet中的方法分发的方法,来实现一个对象对应一个Servlet的操作代码,将所有的Servlet代码都写在一个Servlet中,通过其他的Servlet封装成方法进行调用即可。

1、 创建BaseServlet继承HttpServlet重写service方法

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.Method;

public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1、获取请求路径
        String uri = req.getRequestURI();  // webcore_case_war/brand/selectAll

        //2、获取最后一段路径--方法名
        int index = uri.lastIndexOf('/');
        //获取方法名
        //直接使用index会包含/
        String methodName = uri.substring(index + 1);

        //3、执行方法
        //3.1、获取方法的class类文件
        //哪个方法调用这个service,这个this就代表哪个方法的对象
        //例如BrandServlet和UserServlet,两个Servlet对象,这两个Servlet继承BaseServlet,都会调用这个service方法
        //如果是BrandServlet中的selectAll方法调用service方法,那么这个this就代表BrandServlet对象
        Class<? extends BaseServlet> cls = this.getClass();

        try {
            //3.2、通过class文件反射,获取方法
            //(方法名称,方法携带的参数)方法携带的参数HttpServletRequest、HttpServletResponse也要加进去
            //每个方法都会携带参数HttpServletRequest、HttpServletResponse
            Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);

            //3.3、获取方法后执行方法
            //方法反射告诉对象调用这个方法  方法名.invoke(对象名,携带的参数)
            method.invoke(this,req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

2、创建不同对象的Servlet将不同的Servlet封装成方法

通过/brand/* *号通配符,需要访问那个功能就将方法名替换*号

import com.alibaba.fastjson.JSON;
import com.itheima.pojo.Brand;
import com.itheima.service.impl.BrandServiceImpl;

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

@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet{

    //实现类要创建对象才能调用
    private BrandServiceImpl brandService = new BrandServiceImpl();

    public void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        //通过service方法返回sql结果
        List<Brand> brandList = brandService.selectAll();

        //将返回的结果响应到页面
        //将List集合转换为JSON
        String brands = JSON.toJSONString(brandList);

        //将结果相应到页面
        resp.setContentType("text/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.write(brands);
    }

    public void addBrand(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        //获取前端数据,前端数据是以JSON格式提交的,使用流读取
        BufferedReader reader = req.getReader();
        String s = reader.readLine(); //对应的JSON字符串
        //将对应的JSON字符串转为java对象
        Brand brand = JSON.parseObject(s, Brand.class);

        //将获取的数据封装到数据库
        brandService.addBrand(brand);

        //响应成功的标识
        resp.getWriter().write("success");
    }
}

4、删除品牌

 前端逻辑

//删除按钮
               handleDelete(row) {
                this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
                    cancelButtonText: '取消',
                    confirmButtonText: '确定',
                    type: 'warning'
                }).then(() => {
                    //异步请求后端删除数据
                    var _this = this;
                    axios({
                        method:"post",
                        url:"http://localhost:8080/webEndingCase_war/brand/deleteBrandById",
                        //将一行数据的数据携带传给后端
                        //在html中声明了携带的是id值
                        data:row
                    }).then(function (resp) {
                        //删除逻辑
                        if (resp.data == "success") {
                            //删除成功,自动关闭窗口
                            //刷新数据,重新查询
                            _this.selectAll();
                        }
                    }),
                        this.$message({
                            type: 'success',
                            message: '删除成功!'
                        });
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            },

后端逻辑

public void selectBrandById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{

        //获取前端数据,前端数据是以JSON格式提交的,使用流读取
        BufferedReader reader = req.getReader();
        String id = reader.readLine(); //对应的JSON字符串

        //调用service方法
        Brand brand = brandService.selectBrandById(Integer.parseInt(id));

        //将brand对象转成JSON字符串
        String s = JSON.toJSONString(brand);

        //将JSON字符串发送给前端
        //相应给前端的字符串也要设置编码否则会乱码
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().write(s);
    }

技术难点:

如何获取页面id并将id传递给后端

<!--将一行数据的id藏在操作栏中,通过id就能获取到该行数据-->
        <el-table-column
                prop="id"
                align="center"
                label="操作">
            <!--标签内写按钮-->
            <template slot-scope="scope">
                <!--根据id查询数据,将数据回调回页面-->
                <el-button type="primary" @click="handleSelect(scope.row.id),updatedialogVisible = true">修改</el-button>
                <el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
            </template>
        </el-table-column>

在当前的操作栏隐藏对应的id值

再在对应单元格标签中添加属性 slot-scope="scope",在按钮的点击方法中声明参数scope.row.id,就可以获取该行数据的id值,也可以获取其他值。

       

在vue框架中

5、修改品牌

点击修改后进行数据回显,通过id获取数据响应给前端,修改数据后再点击提交修改,后端实现修改逻辑

 前端逻辑

//提交修改逻辑
            handleUpdate(){
                var _this = this;
                //发送异步请求,携带表单数据
                axios({
                    method: "post",
                    url: "http://localhost:8080/webEndingCase_war/brand/updateBrand",
                    //携带表单数据
                    data:_this.updatebrand
                }).then(function (resp) {
                    //判断后端返回的是否是success字符串
                    if (resp.data == "success") {
                        //添加成功关闭窗口
                        _this.updatedialogVisible = false;

                        //再次查询数据
                        _this.selectAll();

                        //添加成功弹出消息
                        _this.$message({
                            message: '恭喜你,修改成功',
                            type: 'success'
                        })
                    }
                })
            },

            //点击修改后数据回调给页面
            handleSelect(row){
              var _this = this
              //提交异步请求
              //将一行数据的id值传递给后端
              axios({
                  method:"post",
                  url:"http://localhost:8080/webEndingCase_war/brand/selectBrandById",
                  data:row
              }).then(function (resp) {
                  //将回调的数据传给updateBrand模型
                  _this.updatebrand = resp.data;
              })
            },

后端逻辑

public void selectBrandById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{

        //获取前端数据,前端数据是以JSON格式提交的,使用流读取
        BufferedReader reader = req.getReader();
        String id = reader.readLine(); //对应的JSON字符串

        //调用service方法
        Brand brand = brandService.selectBrandById(Integer.parseInt(id));

        //将brand对象转成JSON字符串
        String s = JSON.toJSONString(brand);

        //将JSON字符串发送给前端
        //相应给前端的字符串也要设置编码否则会乱码
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().write(s);
    }

    public void updateBrand(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        //解决前端发送数据乱码问题
        req.setCharacterEncoding("UTF-8");
        //获取前端数据,前端数据是以JSON格式提交的,使用流读取
        BufferedReader reader = req.getReader();
        String s = reader.readLine(); //对应的JSON字符串
        System.out.println(s);
        //将对应的JSON字符串转为java对象
        Brand brand = JSON.parseObject(s, Brand.class);
        System.out.println(brand);
        //调用service
        brandService.updateBrand(brand);

        //修改成功向前端响应标识
        resp.getWriter().write("success");
    }

技术难点:

数据回调传递到前端并展示

遇到的难题:

前端页面返回给后端的JSON中文格式乱码问题

对前端返回的字符串进行输出发现中文格式乱码

解决方法:

在servlet中添加如下代码解决中文乱码问题

req.setCharacterEncoding("UTF-8");

后端返回给前端中文乱码问题

6、批量删除

前端逻辑

 //删除逻辑
                            for (let i = 0; i < this.multipleSelection.length; i++) {
                                let selectionbrand = this.multipleSelection[i];
                                //将选中的id传入deleteIds模型中
                                this.deleteIds[i] = selectionbrand.id;
                            }
                            var _this = this;
                            //发送异步请求,携带表单数据
                            axios({
                                method: "post",
                                url: "http://localhost:8080/webEndingCase_war/brand/deleteBrandByIds",
                                //携带表单数据
                                data: _this.deleteIds
                            }).then(function (resp) {
                                //判断后端返回的是否是success字符串
                                if (resp.data == "success") {

                                    //再次查询数据
                                    _this.selectAll();
                                }
                            })

后端逻辑

public void deleteBrandByIds(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        //接收前端数据  id数组[1,2,8]
        BufferedReader reader = req.getReader();
        String params = reader.readLine();

        //将得到的JSON格式的id数组转为int型数组
        int[] ids = JSON.parseObject(params, int[].class);

        //调用service方法
        brandService.deleteBrandByIds(ids);

        //响应给前端结果

        resp.getWriter().write("success");

    }

技术难点:

获取前端页面复选框选中的id数组,传递给后端

7、分页查询

前端逻辑

//查询分页数据
            selectByPage() {
                var _this = this;
                axios({
                    method:"get",
                    url:"http://localhost:8080/webEndingCase_war/brand/selectByPage?currentPage="+_this.currentPage+"&pageSize="+_this.pageSize
                }).then(function (resp) {
                    //_this.tableData = resp.data; 当前后端传递的数据是{"pageData":[{"brandName":"联想","companyName":"联想有限公司"}
                    //JSON字符串格式,不能直接放入表格
                    //通过resp.data. 来获取不同的数据
                    _this.tableData = resp.data.pageData;
                    _this.totalCount = resp.data.totalCount;
                })
            },

            handleCurrentChange(val) {
                console.log(`当前页: ${val}`);
                //点击切换当前页,赋值给当前页模型
                this.currentPage = val;
                this.selectByPage();
            },
            //分页方法
            handleSizeChange(val) {
                console.log(`每页 ${val} 条`);
                this.pageSize = val;
                this.selectByPage();
            },

后端逻辑

public void selectByPage(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
        //前端通过get请求  使用url将当前页码和当前页数据传到后端 url?currentPage=1&pageSize=10
        String currentPage = req.getParameter("currentPage");
        String pageSize = req.getParameter("pageSize");

        //调用service方法
        PageBean<Brand> pageBean = brandService.selectByPage(Integer.parseInt(currentPage), Integer.parseInt(pageSize));

        //将java对象转成JSON格式
        String jsonString = JSON.toJSONString(pageBean);

        //将JSON数据发送给前端
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().write(jsonString);
    }

技术难点:

需要将当前分页页面数据和总数据条数封装成对象一起传递到前端

8、多条件分页查询

将查询全部、分页查询和多条件查询进行整合,使他们都使用同一个方法

 前端逻辑

修改selectAll方法的查询逻辑,在url后面拼字符串,并且以post请求方式将多条件查询的参数传给后端,参数封装成了selectBrand模型,将来一访问页面就会进行默认的分页查询

//查询分页数据
            selectByPage() {
                axios({
                    //在then的外面可以直接使用this
                    method:"post",
                    url:"http://localhost:8080/webEndingCase_war/brand/selectByPageAndCondition?currentPage="+this.currentPage+"&pageSize="+this.pageSize,
                    data:this.selectBrand
                }).then(resp => {
                    //_this.tableData = resp.data; 当前后端传递的数据是{"pageData":[{"brandName":"联想","companyName":"联想有限公司"}
                    //JSON字符串格式,不能直接放入表格
                    //通过resp.data. 来获取不同的数据
                    this.tableData = resp.data.pageData;
                    this.totalCount = resp.data.totalCount;
                })
            },

后端逻辑

public void selectByPageAndCondition(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{

        req.setCharacterEncoding("UTF-8");

        //前端通过get请求  使用url将当前页码和当前页数据传到后端 url?currentPage=1&pageSize=10
        String currentPage = req.getParameter("currentPage");
        String pageSize = req.getParameter("pageSize");

        System.out.println(currentPage);
        //获取前端对应的查询条件对象
        //接收前端数据
        BufferedReader reader = req.getReader();
        String params = reader.readLine();
        System.out.println(params);
        //将得到的JSON格式转为brand对象
        Brand brand = JSON.parseObject(params,Brand.class);
        System.out.println(brand);

        //调用service方法
        PageBean<Brand> pageBean = brandService.selectByPageAndCondition(Integer.parseInt(currentPage), Integer.parseInt(pageSize),brand);
        System.out.println(pageBean);

        //将java对象转成JSON格式
        String jsonString = JSON.toJSONString(pageBean);

        //将JSON数据发送给前端
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().write(jsonString);
    }

技术难点:

多条件查询后还要通过分页查询展示数据

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值