• JavaWeb、终章案例


    目录

    一、环境搭建

    二、编写前端页面

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

    1、查询所有

            2、新增

            3、代码优化

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

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

            4、删除品牌

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

            5、修改品牌

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

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

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

            6、批量删除

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

            7、分页查询

            8、多条件分页查询

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


    一、环境搭建

    参照 Web案例

    在pom.xml中再导入fastjson坐标

    1. <dependency>
    2. <groupId>com.alibabagroupId>
    3. <artifactId>fastjsonartifactId>
    4. <version>1.2.62version>
    5. dependency>

    二、编写前端页面

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

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

    1、查询所有

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

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

    1. data() {
    2. return {
    3. //当前页码
    4. currentPage: 1,
    5. //对话框默认为false隐藏
    6. dialogVisible: false,
    7. //品牌模型数据
    8. brand: {
    9. status: '',
    10. brandName: '',
    11. companyName:'',
    12. id:'',
    13. ordered:'',
    14. description:''
    15. },
    16. //表格数据模型
    17. tableData: [{
    18. brandName: '三只松鼠',
    19. companyName: '三只松鼠',
    20. description: 'dsds',
    21. ordered: '10',
    22. status: '1',
    23. }],
    24. /*复选框选中的数据集合*/
    25. multipleSelection: []
    26. }
    27. }

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

    1. <el-table
    2. :data="tableData"
    3. style="width: 100%"
    4. @Selection-change="handleSelectionChange"
    5. :row-class-name="tableRowClassName">
    6. <el-table-column
    7. type="selection"
    8. width="55">
    9. el-table-column>
    10. <el-table-column
    11. type="index"
    12. width="50">
    13. el-table-column>
    14. <el-table-column
    15. //对应模型中的名称
    16. prop="brandName"
    17. label="品牌名称"
    18. align="center">
    19. el-table-column>
    20. <el-table-column
    21. prop="companyName"
    22. label="企业名称"
    23. align="center">
    24. el-table-column>
    25. <el-table-column
    26. prop="description"
    27. label="企业描述"
    28. align="center">
    29. el-table-column>
    30. <el-table-column
    31. prop="ordered"
    32. align="center"
    33. label="排序">
    34. el-table-column>
    35. <el-table-column
    36. prop="status"
    37. align="center"
    38. label="当前状态">
    39. el-table-column>
    40. <el-table-column
    41. align="center"
    42. label="操作">
    43. <el-row>
    44. <el-button type="primary">修改el-button>
    45. <el-button type="danger">删除el-button>
    46. el-row>
    47. el-table-column>
    48. el-table>

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

    1. mounted(){
    2. //页面加载完成后发送异步请求获取数据
    3. this.selectAll();
    4. },
    5. methods: {
    6. //查询所有数据
    7. selectAll(){
    8. var _this=this
    9. //页面加载完成后发送异步请求获取数据
    10. axios({
    11. method:"get",
    12. url:"http://localhost:8080/webcore_case_war/brand/selectAll"
    13. }).then(function (resp){
    14. //将后端数据传递给前端模型
    15. _this.tableData = resp.data;
    16. })
    17. },

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

    后端Servlet的逻辑

    1. //通过service方法返回sql结果
    2. List brandList = brandService.selectAll();
    3. //将返回的结果响应到页面
    4. //将List集合转换为JSON
    5. String brands = JSON.toJSONString(brandList);
    6. //将结果相应到页面
    7. resp.setContentType("text/json;charset=utf-8");
    8. PrintWriter writer = resp.getWriter();
    9. writer.write(brands);

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

    2、新增

    前端代码

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

    1. <el-dialog
    2. title="添加品牌"
    3. :visible.sync="dialogVisible"
    4. width="30%"
    5. :before-close="handleClose">
    6. <el-form ref="form" :model="brand" label-width="80px">
    7. <el-form-item label="品牌名称">
    8. <el-input v-model="brand.brandName">el-input>
    9. el-form-item>
    10. <el-form-item label="企业名称">
    11. <el-input v-model="brand.companyName">el-input>
    12. el-form-item>
    13. <el-form-item label="排序">
    14. <el-input v-model="brand.ordered">el-input>
    15. el-form-item>
    16. <el-form-item label="企业描述">
    17. <el-input type="textarea" v-model="brand.description">el-input>
    18. el-form-item>
    19. <el-form-item label="状态">
    20. <el-switch v-model="brand.status"
    21. //按钮的switch逻辑开启按钮表示status为1
    22. active-value="1"
    23. inactive-value="0">
    24. el-switch>
    25. el-form-item>
    26. <el-form-item>
    27. <el-button type="primary" @click="addBrand">立即创建el-button>
    28. <el-button @click="dialogVisible = false">取消el-button>
    29. el-form-item>
    30. el-form>
    31. span>
    32. el-dialog>

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

    1. //提交新增数据
    2. addBrand() {
    3. var _this = this;
    4. //发送异步请求,携带表单数据
    5. axios({
    6. method:"post",
    7. url:"http://localhost:8080/webcore_case_war/brand/addBrand",
    8. //携带表单数据
    9. data:_this.brand
    10. }).then(function (resp){
    11. //判断后端返回的是否是success字符串
    12. if (resp.data == "success"){
    13. //添加成功关闭窗口
    14. _this.dialogVisible = false;
    15. //再次查询数据
    16. _this.selectAll();
    17. //添加成功弹出消息
    18. _this.$message({
    19. message: '恭喜你,添加成功',
    20. type: 'success'
    21. })
    22. }
    23. })
    24. },

    后端逻辑

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

    1. //获取前端数据,前端数据是以JSON格式提交的,使用流读取
    2. BufferedReader reader = req.getReader();
    3. String s = reader.readLine(); //对应的JSON字符串
    4. //将对应的JSON字符串转为java对象
    5. Brand brand = JSON.parseObject(s, Brand.class);
    6. //将获取的数据封装到数据库
    7. brandService.addBrand(brand);
    8. //响应成功的标识
    9. resp.getWriter().write("success");

    3、代码优化

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

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

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

    1. import javax.servlet.ServletException;
    2. import javax.servlet.http.HttpServlet;
    3. import javax.servlet.http.HttpServletRequest;
    4. import javax.servlet.http.HttpServletResponse;
    5. import java.io.IOException;
    6. import java.lang.reflect.Method;
    7. public class BaseServlet extends HttpServlet {
    8. @Override
    9. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    10. //1、获取请求路径
    11. String uri = req.getRequestURI(); // webcore_case_war/brand/selectAll
    12. //2、获取最后一段路径--方法名
    13. int index = uri.lastIndexOf('/');
    14. //获取方法名
    15. //直接使用index会包含/
    16. String methodName = uri.substring(index + 1);
    17. //3、执行方法
    18. //3.1、获取方法的class类文件
    19. //哪个方法调用这个service,这个this就代表哪个方法的对象
    20. //例如BrandServlet和UserServlet,两个Servlet对象,这两个Servlet继承BaseServlet,都会调用这个service方法
    21. //如果是BrandServlet中的selectAll方法调用service方法,那么这个this就代表BrandServlet对象
    22. Classextends BaseServlet> cls = this.getClass();
    23. try {
    24. //3.2、通过class文件反射,获取方法
    25. //(方法名称,方法携带的参数)方法携带的参数HttpServletRequest、HttpServletResponse也要加进去
    26. //每个方法都会携带参数HttpServletRequest、HttpServletResponse
    27. Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
    28. //3.3、获取方法后执行方法
    29. //方法反射告诉对象调用这个方法 方法名.invoke(对象名,携带的参数)
    30. method.invoke(this,req,resp);
    31. } catch (Exception e) {
    32. e.printStackTrace();
    33. }
    34. }
    35. }

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

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

    1. import com.alibaba.fastjson.JSON;
    2. import com.itheima.pojo.Brand;
    3. import com.itheima.service.impl.BrandServiceImpl;
    4. import javax.servlet.ServletException;
    5. import javax.servlet.annotation.WebServlet;
    6. import javax.servlet.http.HttpServletRequest;
    7. import javax.servlet.http.HttpServletResponse;
    8. import java.io.BufferedReader;
    9. import java.io.IOException;
    10. import java.io.PrintWriter;
    11. import java.util.List;
    12. @WebServlet("/brand/*")
    13. public class BrandServlet extends BaseServlet{
    14. //实现类要创建对象才能调用
    15. private BrandServiceImpl brandService = new BrandServiceImpl();
    16. public void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    17. //通过service方法返回sql结果
    18. List brandList = brandService.selectAll();
    19. //将返回的结果响应到页面
    20. //将List集合转换为JSON
    21. String brands = JSON.toJSONString(brandList);
    22. //将结果相应到页面
    23. resp.setContentType("text/json;charset=utf-8");
    24. PrintWriter writer = resp.getWriter();
    25. writer.write(brands);
    26. }
    27. public void addBrand(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    28. //获取前端数据,前端数据是以JSON格式提交的,使用流读取
    29. BufferedReader reader = req.getReader();
    30. String s = reader.readLine(); //对应的JSON字符串
    31. //将对应的JSON字符串转为java对象
    32. Brand brand = JSON.parseObject(s, Brand.class);
    33. //将获取的数据封装到数据库
    34. brandService.addBrand(brand);
    35. //响应成功的标识
    36. resp.getWriter().write("success");
    37. }
    38. }

    4、删除品牌

     前端逻辑

    1. //删除按钮
    2. handleDelete(row) {
    3. this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
    4. cancelButtonText: '取消',
    5. confirmButtonText: '确定',
    6. type: 'warning'
    7. }).then(() => {
    8. //异步请求后端删除数据
    9. var _this = this;
    10. axios({
    11. method:"post",
    12. url:"http://localhost:8080/webEndingCase_war/brand/deleteBrandById",
    13. //将一行数据的数据携带传给后端
    14. //在html中声明了携带的是id值
    15. data:row
    16. }).then(function (resp) {
    17. //删除逻辑
    18. if (resp.data == "success") {
    19. //删除成功,自动关闭窗口
    20. //刷新数据,重新查询
    21. _this.selectAll();
    22. }
    23. }),
    24. this.$message({
    25. type: 'success',
    26. message: '删除成功!'
    27. });
    28. }).catch(() => {
    29. this.$message({
    30. type: 'info',
    31. message: '已取消删除'
    32. });
    33. });
    34. },

    后端逻辑

    1. public void selectBrandById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    2. //获取前端数据,前端数据是以JSON格式提交的,使用流读取
    3. BufferedReader reader = req.getReader();
    4. String id = reader.readLine(); //对应的JSON字符串
    5. //调用service方法
    6. Brand brand = brandService.selectBrandById(Integer.parseInt(id));
    7. //将brand对象转成JSON字符串
    8. String s = JSON.toJSONString(brand);
    9. //将JSON字符串发送给前端
    10. //相应给前端的字符串也要设置编码否则会乱码
    11. resp.setContentType("text/json;charset=utf-8");
    12. resp.getWriter().write(s);
    13. }

    技术难点:

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

    1. <el-table-column
    2. prop="id"
    3. align="center"
    4. label="操作">
    5. <template slot-scope="scope">
    6. <el-button type="primary" @click="handleSelect(scope.row.id),updatedialogVisible = true">修改el-button>
    7. <el-button type="danger" @click="handleDelete(scope.row.id)">删除el-button>
    8. template>
    9. el-table-column>

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

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

           

    在vue框架中

    5、修改品牌

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

     前端逻辑

    1. //提交修改逻辑
    2. handleUpdate(){
    3. var _this = this;
    4. //发送异步请求,携带表单数据
    5. axios({
    6. method: "post",
    7. url: "http://localhost:8080/webEndingCase_war/brand/updateBrand",
    8. //携带表单数据
    9. data:_this.updatebrand
    10. }).then(function (resp) {
    11. //判断后端返回的是否是success字符串
    12. if (resp.data == "success") {
    13. //添加成功关闭窗口
    14. _this.updatedialogVisible = false;
    15. //再次查询数据
    16. _this.selectAll();
    17. //添加成功弹出消息
    18. _this.$message({
    19. message: '恭喜你,修改成功',
    20. type: 'success'
    21. })
    22. }
    23. })
    24. },
    25. //点击修改后数据回调给页面
    26. handleSelect(row){
    27. var _this = this
    28. //提交异步请求
    29. //将一行数据的id值传递给后端
    30. axios({
    31. method:"post",
    32. url:"http://localhost:8080/webEndingCase_war/brand/selectBrandById",
    33. data:row
    34. }).then(function (resp) {
    35. //将回调的数据传给updateBrand模型
    36. _this.updatebrand = resp.data;
    37. })
    38. },

    后端逻辑

    1. public void selectBrandById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    2. //获取前端数据,前端数据是以JSON格式提交的,使用流读取
    3. BufferedReader reader = req.getReader();
    4. String id = reader.readLine(); //对应的JSON字符串
    5. //调用service方法
    6. Brand brand = brandService.selectBrandById(Integer.parseInt(id));
    7. //将brand对象转成JSON字符串
    8. String s = JSON.toJSONString(brand);
    9. //将JSON字符串发送给前端
    10. //相应给前端的字符串也要设置编码否则会乱码
    11. resp.setContentType("text/json;charset=utf-8");
    12. resp.getWriter().write(s);
    13. }
    14. public void updateBrand(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    15. //解决前端发送数据乱码问题
    16. req.setCharacterEncoding("UTF-8");
    17. //获取前端数据,前端数据是以JSON格式提交的,使用流读取
    18. BufferedReader reader = req.getReader();
    19. String s = reader.readLine(); //对应的JSON字符串
    20. System.out.println(s);
    21. //将对应的JSON字符串转为java对象
    22. Brand brand = JSON.parseObject(s, Brand.class);
    23. System.out.println(brand);
    24. //调用service
    25. brandService.updateBrand(brand);
    26. //修改成功向前端响应标识
    27. resp.getWriter().write("success");
    28. }

    技术难点:

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

    遇到的难题:

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

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

    解决方法:

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

    req.setCharacterEncoding("UTF-8");

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

    6、批量删除

    前端逻辑

    1. //删除逻辑
    2. for (let i = 0; i < this.multipleSelection.length; i++) {
    3. let selectionbrand = this.multipleSelection[i];
    4. //将选中的id传入deleteIds模型中
    5. this.deleteIds[i] = selectionbrand.id;
    6. }
    7. var _this = this;
    8. //发送异步请求,携带表单数据
    9. axios({
    10. method: "post",
    11. url: "http://localhost:8080/webEndingCase_war/brand/deleteBrandByIds",
    12. //携带表单数据
    13. data: _this.deleteIds
    14. }).then(function (resp) {
    15. //判断后端返回的是否是success字符串
    16. if (resp.data == "success") {
    17. //再次查询数据
    18. _this.selectAll();
    19. }
    20. })

    后端逻辑

    1. public void deleteBrandByIds(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    2. //接收前端数据 id数组[1,2,8]
    3. BufferedReader reader = req.getReader();
    4. String params = reader.readLine();
    5. //将得到的JSON格式的id数组转为int型数组
    6. int[] ids = JSON.parseObject(params, int[].class);
    7. //调用service方法
    8. brandService.deleteBrandByIds(ids);
    9. //响应给前端结果
    10. resp.getWriter().write("success");
    11. }

    技术难点:

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

    7、分页查询

    前端逻辑

    1. //查询分页数据
    2. selectByPage() {
    3. var _this = this;
    4. axios({
    5. method:"get",
    6. url:"http://localhost:8080/webEndingCase_war/brand/selectByPage?currentPage="+_this.currentPage+"&pageSize="+_this.pageSize
    7. }).then(function (resp) {
    8. //_this.tableData = resp.data; 当前后端传递的数据是{"pageData":[{"brandName":"联想","companyName":"联想有限公司"}
    9. //JSON字符串格式,不能直接放入表格
    10. //通过resp.data. 来获取不同的数据
    11. _this.tableData = resp.data.pageData;
    12. _this.totalCount = resp.data.totalCount;
    13. })
    14. },
    15. handleCurrentChange(val) {
    16. console.log(`当前页: ${val}`);
    17. //点击切换当前页,赋值给当前页模型
    18. this.currentPage = val;
    19. this.selectByPage();
    20. },
    21. //分页方法
    22. handleSizeChange(val) {
    23. console.log(`每页 ${val} 条`);
    24. this.pageSize = val;
    25. this.selectByPage();
    26. },

    后端逻辑

    1. public void selectByPage(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
    2. //前端通过get请求 使用url将当前页码和当前页数据传到后端 url?currentPage=1&pageSize=10
    3. String currentPage = req.getParameter("currentPage");
    4. String pageSize = req.getParameter("pageSize");
    5. //调用service方法
    6. PageBean pageBean = brandService.selectByPage(Integer.parseInt(currentPage), Integer.parseInt(pageSize));
    7. //将java对象转成JSON格式
    8. String jsonString = JSON.toJSONString(pageBean);
    9. //将JSON数据发送给前端
    10. resp.setContentType("text/json;charset=utf-8");
    11. resp.getWriter().write(jsonString);
    12. }

    技术难点:

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

    8、多条件分页查询

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

     前端逻辑

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

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

    后端逻辑

    1. public void selectByPageAndCondition(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
    2. req.setCharacterEncoding("UTF-8");
    3. //前端通过get请求 使用url将当前页码和当前页数据传到后端 url?currentPage=1&pageSize=10
    4. String currentPage = req.getParameter("currentPage");
    5. String pageSize = req.getParameter("pageSize");
    6. System.out.println(currentPage);
    7. //获取前端对应的查询条件对象
    8. //接收前端数据
    9. BufferedReader reader = req.getReader();
    10. String params = reader.readLine();
    11. System.out.println(params);
    12. //将得到的JSON格式转为brand对象
    13. Brand brand = JSON.parseObject(params,Brand.class);
    14. System.out.println(brand);
    15. //调用service方法
    16. PageBean pageBean = brandService.selectByPageAndCondition(Integer.parseInt(currentPage), Integer.parseInt(pageSize),brand);
    17. System.out.println(pageBean);
    18. //将java对象转成JSON格式
    19. String jsonString = JSON.toJSONString(pageBean);
    20. //将JSON数据发送给前端
    21. resp.setContentType("text/json;charset=utf-8");
    22. resp.getWriter().write(jsonString);
    23. }

    技术难点:

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

     

  • 相关阅读:
    【Typora】解决单词爆红问题
    2023 “华为杯” 中国研究生数学建模竞赛(D题)深度剖析|数学建模完整代码+建模过程全解全析
    阿里巴巴Java方向面试题汇总(含答案)
    写了一款Jetbrains插件,为了Markdown
    设计模式 煎饼果子和装饰者模式
    【Qt】对话框QDialog
    企业数据图表- FineReport函数计算组成和语法概述
    金九银十必问Java面试题
    Android 14 系统启动流程 之 启动init进程、启动Zygote进程
    umi4项目:支持适配IE浏览器
  • 原文地址:https://blog.csdn.net/m0_56044262/article/details/126577281