SpringBoot(RESTful,统一响应结构,输出日志,增删改查功能,分页功能,批量删除,常见bug)【详解】

目录

一、准备工作

1. 前后端分离开发流程

2. 开发规范

1.RESTful请求风格

2.统一响应结果

3.代码中输出日志

二、部门管理(增删改查功能)

1. 查询部门列表

2. 删除部门

3. 新增部门

4. 修改部门

三、员工管理(分页功能和批量删除)

1. PageHelper插件

2. 分页查询员工-带条件

3. 删除员工-批量删

四、常见bug

1. Invalid bound statement (not found)

2. Unable to find a @SpringBootConfiguration,you need to use @ContextConfiguration

3. Mapped Statements already contains value: com.itheima.mapper.DeptMapper.selectList

4. Bad Sql Grammer... You have a error in your sql Syntax

5. 其它错误


一、准备工作

1. 前后端分离开发流程

2. 开发规范

所有的项目规范,==并非==全世界统一的强制性规范。实际开发中,可能每个项目组都有自己的一套规范

1.RESTful请求风格

  • 接收请求路径里的变量参数:@PathVariable("占位符名称")

  • 接收不同请求方式的请求:

    • @GetMpping

    • @PostMapping

    • @PutMapping

    • @DeleteMapping

2.统一响应结果

我们这次案例练习里,所有Controller的方法返回值,统一都是Result类型

3.代码中输出日志

企业开发中,通常是要输出日志,为将来程序出bug之后,找线索做准备

传统的方式:在类里添加以下代码,然后才可以使用log.info(), log.warn(), log.error()等方法

private static final Logger log = LoggerFactory.getLogger(当前类名.class);

例如:

@RestController
public class DeptController {
	private static final Logger log = LoggerFactory.getLogger(DeptController.class);
    
    @GetMapping("xxx/{id}")
    public Result xxx(@PathVariable("id") String id){
        //打印日志:根据id查询部门,id=id值
        log.info("根据id查询部门,id={}", id);
        //完成功能代码……
        return null;
    }
}

可以使用Lombok简化一下:

  1. 在类上添加注解 @Slf4j

  2. 在方法里就可以直接使用log对象输出日志了:可以使用log.info(), log.warn(), log.error()等方法

@Slf4j
@RestController
public class DeptController {

    @GetMapping("xxx/{id}")
    public Result xxx(@PathVariable("id") String id){
        //打印日志:根据id查询部门,id=id值
        log.info("根据id查询部门,id={}", id);
        //完成功能代码……
        return null;
    }
}

二、部门管理(增删改查功能)

1. 查询部门列表

DeptController:

package com.itheima.controller;

import com.itheima.pojo.Dept;
import com.itheima.pojo.Emp;
import com.itheima.pojo.Result;
import com.itheima.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 通常会在Controller类上加@RequestMapping("所有方法的路径前缀")
 * 然后每个方法上再添加@RequestMapping、@PostMapping、@PutMapping、@DeleteMapping,只需要加后边剩下的那一截路径即可
 * 比如:
 *      类上配置是@RequestMapping("/depts")
 *      方法上的配置是@GetMapping("/{id}")
 *      这时候,此方法的访问路径是:类的路径 + 方法的路径,即: /depts/{id}
 *
 * 部门管理Controller
 */
@Slf4j
@RestController
@RequestMapping("/depts")
public class DeptController {
    @Autowired
    private DeptService deptService;

    @GetMapping
    public Result queryAllDeppts(){
        log.info("查询所有部门");
        List<Dept> empList = deptService.queryAllDepts();
        return Result.success(empList);
    }
}

DeptService:

package com.itheima.service;

import com.itheima.pojo.Dept;
import com.itheima.pojo.Emp;

import java.util.List;

/**
 * 部门管理
 */
public interface DeptService {
    List<Dept> queryAllDepts();
}

DeptServiceImpl:

package com.itheima.service.impl;

import com.itheima.mapper.DeptMapper;
import com.itheima.pojo.Dept;
import com.itheima.pojo.Emp;
import com.itheima.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;

    @Override
    public List<Dept> queryAllDepts() {
        return deptMapper.selectAll();
    }
}

DeptMapper:

package com.itheima.mapper;

import com.itheima.pojo.Dept;
import com.itheima.pojo.Emp;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * 部门管理
 */
@Mapper
public interface DeptMapper {
    @Select("select * from dept")
    List<Dept> selectAll();
}

2. 删除部门

DeptController:

@DeleteMapping("/{deptId}")
public Result deleteDeptById(@PathVariable("deptId") Integer id){
    log.info("根据id删除部门,id={}", id);
    deptService.deleteDeptById(id);
    return Result.success();
}

DeptService:

void deleteDeptById(Integer id);

DeptServiceImpl:

@Override
public void deleteDeptById(Integer id) {
    deptMapper.deleteById(id);
}

DeptMapper:

@Delete("delete from dept where id = #{id}")
void deleteById(Integer id);

3. 新增部门

DeptController:

@PostMapping
public Result addDept(@RequestBody Dept dept){
    log.info("新增部门:{}", dept);
    deptService.addDept(dept);
    return Result.success();
}

DeptService:

void addDept(Dept dept);

DeptServiceImpl:

@Override
public void addDept(Dept dept) {
    //补全数据
    LocalDateTime now = LocalDateTime.now();
    dept.setCreateTime(now);
    dept.setUpdateTime(now);
    deptMapper.insert(dept);
}

DeptMapper:

@Insert("INSERT INTO dept (name, create_time, update_time) " +
        "VALUES (#{name}, #{createTime}, #{updateTime})")
void insert(Dept dept);

4. 修改部门

DeptController:

@GetMapping("/depts/{id}")
    public Result findById(@PathVariable("id") Integer id) {
        Dept dept = deptService.findById(id);
        return Result.success(dept);
    }

    @PutMapping("/depts")
    public Result edit(@RequestBody Dept dept){
        boolean success = deptService.updateById(dept);
        if (success) {
            return Result.success();
        }else{
            return Result.error("修改部门失败");
        }
    }

DeptService:

Dept findById(Integer id);

boolean updateById(Dept dept);

DeptServiceImpl:

@Override
    public Dept findById(Integer id) {
        return deptMapper.findById(id);
}

@Override
 public boolean updateById(Dept dept) {
        dept.setUpdateTime(LocalDateTime.now());

        return deptMapper.updateById(dept);
}

DeptMapper:

@Select("select * from dept where id = #{id}")
Dept findById(Integer id);

@Update("update dept set name=#{name}, update_time=#{updateTime} where id = #{id}")
boolean updateById(Dept dept);

三、员工管理(分页功能和批量删除)

1. PageHelper插件

分页功能介绍

分页查询功能,客户端通常需要我们提供两项数据:

  • 数据列表:用于展示给用户看的数据;用户每次点击某一页的按钮,就要去服务端加载这一页的数据列表

  • 总数量:客户端得到总数量后,可以根据每页几条计算分了多少页,从而显示页码按钮

原始分页功能的实现方式

服务端要准备以上两项数据,需要:

  • 执行SQL语句查询总数量:select count(*) from emp where gender = 1

  • 执行SQL语句查询数据列表:select * from emp where gender = 1 limit 0, 5

存在的问题:

  1. 有两条SQL语句,Mapper接口里要写两个方法;

  2. 两条SQL语句的where条件相同

PageHelper介绍

分页插件PageHelper官网:MyBatis 分页插件 PageHelper

PageHelper是一款开源的Mybatis插件,可以帮我们简化分页功能的实现

PageHelper的使用

1.添加依赖坐标

<!--PageHelper分页插件-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.4.2</version>
</dependency>

2.使用方式:在调用Mapper时,按照如下步骤

//1. 开启分页
PageHelper.startPage(页码,每页几条);
//2. 查询列表:SQL语句里不要加limit,只要查询列表就行.
//   例如 select * from emp where...    不要再加limit
List<Emp> empList = empMapper.selectList();
//3. 获取分页结果
Page<Emp> page = (Page<Emp>)empList;
long total = page.getTotal(); //获取总数量

PageHelper底层原理:

2. 分页查询员工-带条件

根据页面提交的搜索条件,分页查询员工列表

EmpController:

package com.itheima.controller;

import com.itheima.pojo.Emp;
import com.itheima.pojo.PageBean;
import com.itheima.pojo.Result;
import com.itheima.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;

/**
 * 员工管理Controller
 */
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
    @Autowired
    private EmpService empService;

    @GetMapping
    public Result queryEmpsByPage(@RequestParam(value = "page", defaultValue = "1") Integer page,
                                  @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
                                  String name, Integer gender,
                                  @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                                  @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){

        PageBean<Emp> pageBean = empService.queryEmpsByPage(name, gender, begin, end, page, pageSize);
        return Result.success(pageBean);
    }
}

EmpService:

public interface EmpService {
    PageBean<Emp> queryEmpsByPage(String name, Integer gender, LocalDate begin, LocalDate end, Integer page, Integer pageSize);
}

EmpServiceImpl:

package com.itheima.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.Emp;
import com.itheima.pojo.PageBean;
import com.itheima.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;

@Service
public class EmpServiceImpl implements EmpService {
    @Autowired
    private EmpMapper empMapper;

    @Override
    public PageBean<Emp> queryEmpsByPage(String name, Integer gender, LocalDate begin, LocalDate end, Integer page, Integer pageSize) {
        //开启分页
        PageHelper.startPage(page, pageSize);

        //查询列表
        List<Emp> empList = empMapper.selectList(name, gender, begin, end);

        //得到分页结果
        Page<Emp> p = (Page<Emp>) empList;

        //封装PageBean对象
        PageBean<Emp> pageBean = new PageBean<>();
        pageBean.setTotal((int) p.getTotal());
        pageBean.setRows(empList);
        return pageBean;
    }
}

EmpMapper:

package com.itheima.mapper;

import com.itheima.pojo.Emp;
import org.apache.ibatis.annotations.Mapper;

import java.time.LocalDate;
import java.util.List;

/**
 * 员工管理
 */
@Mapper
public interface EmpMapper {
    List<Emp> selectList(String name, Integer gender, LocalDate begin, LocalDate end);
}

EmpMapper.xml:

xml映射文件:要和Mapper接口同名同包

xml内容:

  • mapper标签的namespace必须是Mapper接口的全限定类名;

  • select标签的id必须是对应的方法名

  • select标签必须有resultType,是JavaBean的全限定类名,表示要把查询结果封装成什么类型的对象

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
    <select id="queryByPage" resultType="com.itheima.pojo.Emp">
        select * from emp
        <where>
            <if test="name!=null and name.length()>0">
                and name like concat('%', #{name}, '%')
            </if>
            <if test="gender!=null">
                and gender = #{gender}
            </if>
            <if test="begin!=null">
                and entrydate >= #{begin}
            </if>
            <if test="end!=null">
                <!-- XML的特殊字符:< 要写成 &lt;  -->
                and entrydate &lt;= #{end}
            </if>
        </where>
    </select>

    <delete id="deleteByIds">
        delete from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>
</mapper>

3. 删除员工-批量删

EmpController:

@DeleteMapping("/{ids}")
public Result batchDeleteEmps(@PathVariable("ids") List<Integer> ids){
    empService.batchDeleteEmps(ids);
    return Result.success();
}

EmpService:

void batchDeleteEmps(List<Integer> ids);

EmpServiceImpl:

@Override
public void batchDeleteEmps(List<Integer> ids) {
    empMapper.batchDeleteByIds(ids);
}

EmpMapper:

void batchDeleteByIds(List<Integer> ids);

EmpMapper.xml

<delete id="batchDeleteByIds">
    delete from emp
    <where>
        <if test="ids!=null and ids.size()>0">
            <foreach collection="ids" open="and id in(" item="id" separator="," close=")">
                #{id}
            </foreach>
        </if>
    </where>
</delete>

四、常见bug

1. Invalid bound statement (not found)

原因:Mapper接口里的定义了方法,但是找不到给它配置的SQL语句

解决:如果SQL语句要和方法关联起来,有以下要求,挨个检查确认一下:

  • XML映射文件,必须和Mapper接口同名同位置

  • XML里的mapper标签的namespace必须是Mapper接口的全限定类名

  • XML里配置SQL语句的标签(select, insert, update, delete)的id必须是方法名

2. Unable to find a @SpringBootConfiguration,you need to use @ContextConfiguration

在执行单元测试方法时,出现这个错误

原因:单元测试类不在 引导类所在的包 里边。SpringBoot项目的目录结构是有要求的

SpringBoot工程目录结构要求:

  • 引导类所在的包,必须是最大的包。其它所有类(包括单元测试类)必须全部在这个包下边

  • 比如,引导类在com.itheima包下,那么所有类都必须在这个包下

    • Controller类、Service类、Mapper类、其它类

    • 单元测试测试类等等

3. Mapped Statements already contains value: com.itheima.mapper.DeptMapper.selectList

出现的原因,是因为:这个方法有多个SQL语句配置,配置重复了。或者Mapper里的这个方法有重载(同名方法)

Mapper接口里的方法:所有方法不能同名

4. Bad Sql Grammer... You have a error in your sql Syntax

SQL语句有语法错误,检查SQL语句

5. 其它错误

  1. web工程:服务端必须启动成功后,然后Postman或者前端界面才可以访问成功

    如何启动:运行引导类(启动类),不要运行单元测试类

  2. 常见的HTTP错误码

    404:找不到资源。需要检查:你的请求路径,在Controller里有没有对应的方法存在

    500:服务器内部错误。需要检查:服务端控制台,查看错误信息,根据错误信息定位问题、解决问题

    405:Method Not Allowed,请求方式不允许。通常是 客户端发请求的方式,和Controller方法允许的请求方式不匹配

    • 比如:客户端发请求是 DELETE /depts/1;服务端只有一个方法路径是 @GetMapping("/depts/{id}")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/464273.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数字后端 EDA 软件分享

数字后端 EDA 软件分享 推荐这几家的EDA工具吧&#xff0c;虽说我也支持国产工具&#xff0c;但是我还是选择了这几家的工具 apache cadence mentor synopsys 下图我现在用的eda环境&#xff0c;利用网上的资源&#xff0c;自己独立在vmware上搭建好的EDA环境 除去pdk&#…

MySQL语法分类 DQL(6)分页查询

为了更好的学习这里给出基本表数据用于查询操作 create table student (id int, name varchar(20), age int, sex varchar(5),address varchar(100),math int,english int );insert into student (id,name,age,sex,address,math,english) values (1,马云,55,男,杭州,66,78),…

Matlab/simulink基于模糊PID智能控制的温度控制系统建模仿真

参考文献 Matlab/simulink基于模糊PID智能控制的温度控制系统建模仿真 该系统主要对某小区换热站的温度控制策略和控制方案进行了设计&#xff0c;其设计内 容主要包括三部分。首先是基于模糊PID智能控制的温度控制系统设计。在温度控制 算法方面&#xff0c;该设计于传统的P…

MySQL实战:监控

监控指标 性能类指标 名称说明QPS数据库每秒处理的请求数量TPS数据库每秒处理的事务数量并发数数据库实例当前并行处理的会话数量连接数连接到数据库会话的数量缓存命中率Innodb的缓存命中率 功能类指标 名称说明可用性数据库是否正常对外提供服务阻塞当前是否有阻塞的会话…

操作系统:malloc与堆区内存管理

malloc是函数而不是系统调用&#xff0c;他的底层是同调调用brk和mmap这两个系统调用实现功能的&#xff0c;具体选择brk还是mmap要看申请的空间大小以及malloc中的阈值&#xff08;一般是128kb&#xff09; 注意申请的空间只有使用才会触发缺页中断映射到物理内存 不理解的话先…

搞机笔记 MI8 dipper

刷回MIUI 之前刷了 lineage-19.1-20220728-nightly-dipper-signed 基于安卓12&#xff0c;实现了以下功能 TWRPmagisk & ROOTmicroG 退回MIUI的原因有&#xff1a; lineage 墓碑 管不住APP后台&#xff0c;太卡了MIUI提供了3GB的虚拟内存lineage 不支持人脸识别lineag…

小蓝的漆房——算法思路

题目链接&#xff1a;1.小蓝的漆房 - 蓝桥云课 (lanqiao.cn) 本题只要是通过枚举的方法&#xff0c;算出涂成每一种颜色所需的天数&#xff0c;最后在所有天数中找出最小值&#xff08;由题可知&#xff0c;最多只有60种颜色&#xff0c;所以可以尝试算出每种颜色所需的时间&am…

在雄安新区买新房要注意什么?有哪些注意事项?

雄安新区新建住宅均价每平方米11735元起&#xff0c;二手房每平方米8950元起。 整体价格非常有优势。 雄安新区房价走势与区域发展直接相关。 而且&#xff0c;雄安新区已经成立五周年了。 2022年&#xff0c;雄安新区多项重点项目将陆续竣工。 雄安新区城市基础设施建设已初具…

Spring注解开发(Spring学习笔记六)

1、在Spring4之后&#xff0c;要使用注解开发&#xff0c;必须保证aop包的导入 2、使用注解需要导入context约束&#xff0c;增加注解的支持(没有注解和支持注解是使用不了的) <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http:/…

用尾插的思路实现 “合并两个有序链表”

一、题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&#xff1a; 输入&#xff1a;l1 [], l2 [] 输出&#…

二. CUDA编程入门-CUDA中的线程与线程束

目录 前言0. 简述1. 执行一下我们的第一个CUDA程序2. CUDA中的grid和block3. block和thread的遍历(traverse)4. nvcc编译器5. Makefile部分6. 执行我们的第二个CUDA程序7. Makefile添加的部分总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接…

[C语言]——VS实用调用技巧

一.什么是bug bug本意是“昆⾍”或“⾍⼦”&#xff0c;现在⼀般是指在电脑系统或程序中&#xff0c;隐藏着的⼀些未被发现的缺陷或问题&#xff0c;简称程序漏洞。 “Bug” 的创始⼈格蕾丝赫柏&#xff08;Grace Murray Hopper&#xff09;&#xff0c;她是⼀位为美国海军⼯…

MQ组件之RabbitMQ学习

MQ组件之RabbitMQ入门 同步调用和异步调用 在微服务架构中&#xff0c;服务之间的调用有同步调用和异步调用两种方式。 我们使用OpenFeign去调用是同步调用&#xff0c;同步调用的缺点很明显&#xff0c;在下图的场景中&#xff0c;支付完成后需要调用订单服务、仓库服务、短…

MyBatisPlus 之二:SpringBoot 快速整合 MyBatisPlus 详细步骤

SpringBootMyBatisPlus Spring Boot 结合 MyBatis Plus 是一种常见的 Java 后端开发框架组合&#xff0c;能够快速构建高性能、易于维护的 CRUD 应用程序。以下是 Spring Boot 集成 MyBatis Plus 的基本步骤 一、快速体验 注意&#xff1a;下面版本 idea2020 SpringBoot2.* …

node.js快速入门-day03

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;给自己一个梦想&#xff0c;给世界一个惊喜。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章目录 web服务器创建…

Rocket MQ 从入门到实践

为什么要使用消息队列&#xff0c;解决什么问题&#xff1f;&#xff08;消峰、解藕、异步&#xff09; 消峰填谷 客户端》 网关 〉 消息队列》秒杀服务 异步解耦 消息队列中的重要概念理解。&#xff08;主题、消费组、队列&#xff0c;游标&#xff1f;&#xff09; 主题&…

phpstudy搭建简单渗透测试环境upload-labs、DVWA、sqli-labs靶场

好久没有做渗透相关的试验了&#xff0c;今天打开phpstudy发现很多问题&#xff0c;好多环境都用不了&#xff0c;那就卸载重装吧&#xff0c;顺便记录一下。 小皮下载地址&#xff1a; https://www.xp.cn/download.html 下载安装完成 一、下载搭建upload-labs环境 github…

LeetCode每日一题[C++]-310.最小高度树

题目描述 树是一个无向图&#xff0c;其中任何两个顶点只通过一条路径连接。 换句话说&#xff0c;一个任何没有简单环路的连通图都是一棵树。 给你一棵包含 n 个节点的树&#xff0c;标记为 0 到 n - 1 。给定数字 n 和一个有 n - 1 条无向边的 edges 列表&#xff08;每一个…

数字多空策略(实盘+回测+数据)

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

【深度学习模型移植】用torch普通算子组合替代torch.einsum方法

首先不得不佩服大模型的强大之处&#xff0c;在算法移植过程中遇到einsum算子在ONNX中不支持&#xff0c;因此需要使用普通算子替代。参考TensorRT - 使用torch普通算子组合替代torch.einsum爱因斯坦求和约定算子的一般性方法。可以写出简单的替换方法&#xff0c;但是该方法会…