关于Mybits三层架构的项目操作

发布时间 2023-12-10 22:30:24作者: 奕帆卷卷

概述

本篇文章用来记录如何使用mybits在三层架构中进行简单的增删改查操作,下面我们进入管理系统的场景下进行操作,这个管理系统中的增删改查的大体逻辑基本逻辑。

首先三层架构中

  • colltroller:用来接收和传递参数值
  • service:在这层调用mapper接口中的方法或者回调的函数数据
  • mapper:在这层用来定义SQL语句操作数据库,又或者在resources配置文件夹中,建立同名同包的文件,来映射接口的方法

注意在三层架构中,注重面向接口开发,所以在文件中,一般是面向接口开发,使用privete来定义接口文件对象

注意,特别注意,接口开发要根据 接口文档 开发

注解

在项目开发中我们一般会采用各种依赖来进行简化代码操作,而这种依赖通过注释注解来进行标注

注意:如果想要使用注解,需要引入所对应的依赖

@Data

主要用来提高代码的简洁,这个注解可以自动创建get(),set(),toString()等方法

此注解需要引入Lombok依赖

另外

@AllArgsConstructor : 注在类上,提供类的全参构造
@NoArgsConstructor : 注在类上,提供类的无参构造

优点是可以自动生成各种构造器和方法,缺点是 不支持多种参数构造器的重载

另外Lombok中可以使用@Slf4j:注解在类上,提供对应的Logger对象,变量名为log

@RestController

这注解是专门用来处理Http请求处理的

RestController是Controller的一个衍生注解,@RestController 是 @Controller 和 @ResponseBody两个注解的结合体

我们通常在colltroller中顶层使用这个注释,表名该类中的所有方法都会以JSON/XML的格式返回响应

因为在colltroller层负责数据前端和后端的传递,可以通过其他注释来进行方法路由的标识

  • @GetMapping Get方法的路由
  • @PostMapping POST方法的路由
  • @DeleteMapping DELETE方法的路由
  • @PutMapping put方法的路由

@RequestMapping

当你的这个文件中的路由路径都是相同的时候就可以使用这个注释标注路径,用于映射HTTP请求的路径(post,put,delete,get)

或者在方法上使用注解分别标记具体请求路径

  • @GetMapping
  • @PostMapping
  • @DeleteMapping
  • @PutMapping

列如 在文件头部

@RequestMapping("/customers")

@Autowired

@Autowired 注释可以标注在属性上,方法上,构造器上来完成自动装配。默认是根据属性类型,spring自动将匹配到的属性值进行注入,然后就可以使用这属性

当标注的属性是接口时,其实注入的是这个接口的实现类,如果这个接口又多个实现类,只使用@Autowired就会进行报错,因为它默认是根据类型去找。

@RequestBody

主要用来接收前端传递给后端的数据(请求体)

将HTTP请求的请求体内容绑定到方法参数上,常用于接收JSON和XML格式的请求数据

注意: 需要确保请求的Content-Type和方法的参数类型匹配

@RequestBody和@RequestParam可以同时使用,@RequesBody最多只能有一个,而@RequestParam可以有多个

@ResponseBody

可以用于方法上,标记该方法的返回值作为HTTP响应的内容

注意返回值的数据类型,会根据不同的数据类型进行相应的转换处理,常用于返回JSON,XML等格式的数据

@DateTimeFormat

常用于方法参数上,指定日期时间格式

  @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate begin;//开始时间

@PathVariable

用于方法参数上,用于获取HTTP请求路径中的占位符变量

列如请求路径参数为/{id}

/clazzs/3

项目前期准备

数据库数据表dept准备

响应实体类

package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * 后端统一返回结果
 */
@Data
@NoArgsConstructor  //无参构造
@AllArgsConstructor  //有参构造
public class Result {

    private Integer code; //编码:1成功,0为失败
    private String msg; //错误信息
    private Object data; //数据

    public static Result success() {
        Result result = new Result();
        result.code = 1;
        return result;
    }

    public static Result success(Object object) {
        Result result = new Result();
        result.data = object;
        result.code = 1;
        return result;
    }

    public static Result error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }

}

Dept对象封装实体类

package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor  //无参构造
@AllArgsConstructor  //有参构造
public class Dept {
    private Integer id;
    private String name;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;

}

接口请求类型实体类封装

package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor  //无参构造
@AllArgsConstructor  //有参构造
public class Dept {
    private Integer id;
    private String name;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;

}

注意,层与层之间面向接口开发,实际注入的接口的实现类

    @Autowired
private DeptService deptService;//面向接口编程,多态的体现

查询所有部门操作

controller -> service -> mapper

查询操作的路径为Get,所以在controller层中写接收返回方法时,要在头部加上@GetMapping标识Get方法的路由

 /**
     * 查询部门
     *
     * @throws Exception
     */
    @GetMapping
    public Result list() throws Exception {
        List<Dept> deptList  = deptService.list();
      return Result.success(deptList);

    }

在service层下定义list()方法,在接口的实现类中接收处理的数据

 /**
     * 查看所有部门
     * @return
     */
    @Override
    public List<Dept> list() {
        return deptMapper.findAll();
    }

在mapping接口中,写SQL语句获取或者操作数据内容

    @Select("select *from dept")
    public List<Dept> findAll();

根据id删除操作

本操作需要前端向后端传入id值,所以需要使用参数方法,并且不需要向前端返回数据,所以success()中不需要返回数据

   @DeleteMapping
    public Result delete(Integer id){
        System.out.println("根据ID删除部门;"+id);
        deptService.delete(id);
        return Result.success();
    }

在service层中,定义delete方法,实现类实现,

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

并在mapper层实现SQL操作数据库

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

根据id增加数据

增加数据,在前端页面中像后端传递的是一个对象,增加操作也不需要返回数据

/**
     * 新增部门
     * @param dept
     * @return
     */
    @PostMapping
    public Result add(@RequestBody Dept dept){
        System.out.println("新增部门:"+dept);
        deptService.add(dept);
        return Result.success();
    }

在service层中定义add方法,但因为封装的类中,有时间参数,我们通常将修改时间的数值,使用now()函数获取当前时间传入

  @Override
    public void add(Dept dept) {
        //为基础属性进行赋值
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }

在mapping层写SQL语句

   /**
     * 根据id增加部门数据
     * @param dept
     */
    @Insert("insert into dept(name,create_time,update_time) values(#{name},#{createTime},#{updateTime})")
    void insert(Dept dept);

修改数据

修改数据业务逻辑

前端页面修改页面首先点击数据,此时前端向后端传递id值,后端返回对象数据,前端页面回显数据,前端再进行修改,将修改的数据传入后端数据库,此时,修改完毕后不需要向前端返回数据

根据id获取对象数据

获取数据实际上是查询操作,所有需要返回数据

 @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id){
        System.out.println("根据id查询部门"+id);
        Dept dept = deptService.getById(id);
        return Result.success(dept);
    }

Service层

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

Mapper层

根据接口手册操作返回数据

    @Select("select id,name,create_time,update_time from dept where id = #{id} ")
    Dept getById(Integer id);

修改数据

controller层

    /**
     * 修改部门
     * @param dept
     * @return
     */
    @PutMapping
    public Result update(@RequestBody Dept dept){
    System.out.println("修改部门:"+dept);
    deptService.update(dept);
    return Result.success();
}

Service层

  @Override
    public void update(Dept dept) {
        //补全基础属性
        dept.setUpdateTime(LocalDateTime.now());
        //更新数据
        deptMapper.update(dept);
    }

Mapper层

我们在修改数据时,如果采用@Update的形式,安全性不高,可能会发送SQL注入安全问题,所以我们采用映射文件XML的方式对传参数据安全校验

/**
     * 根据id修改部门数据
     * @param dept
     */
//    @Update("update dept set name = #{name},update_time = #{updateTime} where id = #{id} ")
    //采用映射文件严谨,预防SQL注入
    void update(Dept dept);
}

在resources配置文件中创建XML映射文件

注意

  1. 接口名要和对应的映射文件名称相同,并且路径也相同 (同包同名
  2. 接口中的方法名要和mapper映射文件中唯一标识的id相同
  3. 接口中的全限定名要和mapper映射文件的namespace一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.DeptMapper">
<update id="update">
    update dept
    <set>
        <if test="name !=null and name!=''">
            name = #{name},
        </if>
        <if test="updateTime != null">
            update_time = #{updateTime}
        </if>
    </set>
    where id =#{id}
</update>
</mapper>