当前位置:   article > 正文

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

restful 打印日志

目录

一、准备工作

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);

例如:

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

可以使用Lombok简化一下:

  1. 在类上添加注解 @Slf4j

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

  1. @Slf4j
  2. @RestController
  3. public class DeptController {
  4. @GetMapping("xxx/{id}")
  5. public Result xxx(@PathVariable("id") String id){
  6. //打印日志:根据id查询部门,id=id值
  7. log.info("根据id查询部门,id={}", id);
  8. //完成功能代码……
  9. return null;
  10. }
  11. }

在SpringBoot配置文件里加上:

  1. #logging.level,包名=日志级别 表示指定包下的程序类,只输出指定级别以上的日志
  2. logging.level.com.itheima=error

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

1. 查询部门列表

DeptController:

  1. package com.itheima.controller;
  2. import com.itheima.pojo.Dept;
  3. import com.itheima.pojo.Emp;
  4. import com.itheima.pojo.Result;
  5. import com.itheima.service.DeptService;
  6. import lombok.extern.slf4j.Slf4j;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.web.bind.annotation.*;
  9. import java.util.List;
  10. /**
  11. * 通常会在Controller类上加@RequestMapping("所有方法的路径前缀")
  12. * 然后每个方法上再添加@RequestMapping@PostMapping@PutMapping@DeleteMapping,只需要加后边剩下的那一截路径即可
  13. * 比如:
  14. * 类上配置是@RequestMapping("/depts")
  15. * 方法上的配置是@GetMapping("/{id}")
  16. * 这时候,此方法的访问路径是:类的路径 + 方法的路径,即: /depts/{id}
  17. *
  18. * 部门管理Controller
  19. */
  20. @Slf4j
  21. @RestController
  22. @RequestMapping("/depts")
  23. public class DeptController {
  24. @Autowired
  25. private DeptService deptService;
  26. @GetMapping
  27. public Result queryAllDeppts(){
  28. log.info("查询所有部门");
  29. List<Dept> empList = deptService.queryAllDepts();
  30. return Result.success(empList);
  31. }
  32. }

DeptService:

  1. package com.itheima.service;
  2. import com.itheima.pojo.Dept;
  3. import com.itheima.pojo.Emp;
  4. import java.util.List;
  5. /**
  6. * 部门管理
  7. */
  8. public interface DeptService {
  9. List<Dept> queryAllDepts();
  10. }

DeptServiceImpl:

  1. package com.itheima.service.impl;
  2. import com.itheima.mapper.DeptMapper;
  3. import com.itheima.pojo.Dept;
  4. import com.itheima.pojo.Emp;
  5. import com.itheima.service.DeptService;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.stereotype.Service;
  8. import java.time.LocalDateTime;
  9. import java.util.List;
  10. @Service
  11. public class DeptServiceImpl implements DeptService {
  12. @Autowired
  13. private DeptMapper deptMapper;
  14. @Override
  15. public List<Dept> queryAllDepts() {
  16. return deptMapper.selectAll();
  17. }
  18. }

DeptMapper:

  1. package com.itheima.mapper;
  2. import com.itheima.pojo.Dept;
  3. import com.itheima.pojo.Emp;
  4. import org.apache.ibatis.annotations.Delete;
  5. import org.apache.ibatis.annotations.Insert;
  6. import org.apache.ibatis.annotations.Mapper;
  7. import org.apache.ibatis.annotations.Select;
  8. import java.util.List;
  9. /**
  10. * 部门管理
  11. */
  12. @Mapper
  13. public interface DeptMapper {
  14. @Select("select * from dept")
  15. List<Dept> selectAll();
  16. }

2. 删除部门

DeptController:

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

DeptService:

void deleteDeptById(Integer id);

DeptServiceImpl:

  1. @Override
  2. public void deleteDeptById(Integer id) {
  3. deptMapper.deleteById(id);
  4. }

DeptMapper:

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

3. 新增部门

DeptController:

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

DeptService:

void addDept(Dept dept);

DeptServiceImpl:

  1. @Override
  2. public void addDept(Dept dept) {
  3. //补全数据
  4. LocalDateTime now = LocalDateTime.now();
  5. dept.setCreateTime(now);
  6. dept.setUpdateTime(now);
  7. deptMapper.insert(dept);
  8. }

DeptMapper:

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

4. 修改部门

DeptController:

  1. @GetMapping("/depts/{id}")
  2. public Result findById(@PathVariable("id") Integer id) {
  3. Dept dept = deptService.findById(id);
  4. return Result.success(dept);
  5. }
  6. @PutMapping("/depts")
  7. public Result edit(@RequestBody Dept dept){
  8. boolean success = deptService.updateById(dept);
  9. if (success) {
  10. return Result.success();
  11. }else{
  12. return Result.error("修改部门失败");
  13. }
  14. }

DeptService:

  1. Dept findById(Integer id);
  2. boolean updateById(Dept dept);

DeptServiceImpl:

  1. @Override
  2. public Dept findById(Integer id) {
  3. return deptMapper.findById(id);
  4. }
  5. @Override
  6. public boolean updateById(Dept dept) {
  7. dept.setUpdateTime(LocalDateTime.now());
  8. return deptMapper.updateById(dept);
  9. }

DeptMapper:

  1. @Select("select * from dept where id = #{id}")
  2. Dept findById(Integer id);
  3. @Update("update dept set name=#{name}, update_time=#{updateTime} where id = #{id}")
  4. 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.添加依赖坐标

  1. <!--PageHelper分页插件-->
  2. <dependency>
  3. <groupId>com.github.pagehelper</groupId>
  4. <artifactId>pagehelper-spring-boot-starter</artifactId>
  5. <version>1.4.2</version>
  6. </dependency>

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

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

PageHelper底层原理:

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

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

EmpController:

  1. package com.itheima.controller;
  2. import com.itheima.pojo.Emp;
  3. import com.itheima.pojo.PageBean;
  4. import com.itheima.pojo.Result;
  5. import com.itheima.service.EmpService;
  6. import lombok.extern.slf4j.Slf4j;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.format.annotation.DateTimeFormat;
  9. import org.springframework.web.bind.annotation.GetMapping;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.RequestParam;
  12. import org.springframework.web.bind.annotation.RestController;
  13. import java.time.LocalDate;
  14. /**
  15. * 员工管理Controller
  16. */
  17. @Slf4j
  18. @RestController
  19. @RequestMapping("/emps")
  20. public class EmpController {
  21. @Autowired
  22. private EmpService empService;
  23. @GetMapping
  24. public Result queryEmpsByPage(@RequestParam(value = "page", defaultValue = "1") Integer page,
  25. @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
  26. String name, Integer gender,
  27. @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
  28. @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
  29. PageBean<Emp> pageBean = empService.queryEmpsByPage(name, gender, begin, end, page, pageSize);
  30. return Result.success(pageBean);
  31. }
  32. }

EmpService:

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

EmpServiceImpl:

  1. package com.itheima.service.impl;
  2. import com.github.pagehelper.Page;
  3. import com.github.pagehelper.PageHelper;
  4. import com.itheima.mapper.EmpMapper;
  5. import com.itheima.pojo.Emp;
  6. import com.itheima.pojo.PageBean;
  7. import com.itheima.service.EmpService;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.stereotype.Service;
  10. import java.time.LocalDate;
  11. import java.util.List;
  12. @Service
  13. public class EmpServiceImpl implements EmpService {
  14. @Autowired
  15. private EmpMapper empMapper;
  16. @Override
  17. public PageBean<Emp> queryEmpsByPage(String name, Integer gender, LocalDate begin, LocalDate end, Integer page, Integer pageSize) {
  18. //开启分页
  19. PageHelper.startPage(page, pageSize);
  20. //查询列表
  21. List<Emp> empList = empMapper.selectList(name, gender, begin, end);
  22. //得到分页结果
  23. Page<Emp> p = (Page<Emp>) empList;
  24. //封装PageBean对象
  25. PageBean<Emp> pageBean = new PageBean<>();
  26. pageBean.setTotal((int) p.getTotal());
  27. pageBean.setRows(empList);
  28. return pageBean;
  29. }
  30. }

EmpMapper:

  1. package com.itheima.mapper;
  2. import com.itheima.pojo.Emp;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import java.time.LocalDate;
  5. import java.util.List;
  6. /**
  7. * 员工管理
  8. */
  9. @Mapper
  10. public interface EmpMapper {
  11. List<Emp> selectList(String name, Integer gender, LocalDate begin, LocalDate end);
  12. }

EmpMapper.xml:

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

xml内容:

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

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

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

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.itheima.mapper.EmpMapper">
  6. <select id="queryByPage" resultType="com.itheima.pojo.Emp">
  7. select * from emp
  8. <where>
  9. <if test="name!=null and name.length()>0">
  10. and name like concat('%', #{name}, '%')
  11. </if>
  12. <if test="gender!=null">
  13. and gender = #{gender}
  14. </if>
  15. <if test="begin!=null">
  16. and entrydate >= #{begin}
  17. </if>
  18. <if test="end!=null">
  19. <!-- XML的特殊字符:< 要写成 &lt; -->
  20. and entrydate &lt;= #{end}
  21. </if>
  22. </where>
  23. </select>
  24. <delete id="deleteByIds">
  25. delete from emp where id in
  26. <foreach collection="ids" item="id" separator="," open="(" close=")">
  27. #{id}
  28. </foreach>
  29. </delete>
  30. </mapper>

3. 删除员工-批量删

EmpController:

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

EmpService:

void batchDeleteEmps(List<Integer> ids);

EmpServiceImpl:

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

EmpMapper:

void batchDeleteByIds(List<Integer> ids);

EmpMapper.xml

  1. <delete id="batchDeleteByIds">
  2. delete from emp
  3. <where>
  4. <if test="ids!=null and ids.size()>0">
  5. <foreach collection="ids" open="and id in(" item="id" separator="," close=")">
  6. #{id}
  7. </foreach>
  8. </if>
  9. </where>
  10. </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}")

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/576660
推荐阅读
相关标签
  

闽ICP备14008679号