视频

maven下载和安装,1,2,3

postman安装使用教程,1

– 视频文档链接: https://www.yuque.com/zaibaliweigezidemeixi/dopm5h 密码:mp6h

代码: spring boot: https://github.com/coder-fengzhu/boot-demo mybatis-plus: https://github.com/coder-fengzhu/mp-demo

项目结构

后端

  • api层:接收前端浏览器的客户端http请求–get、post、put、delete(controller层)
  • serveice层:实现具体的业务逻辑,
  • data access层:访问数据库—关系型数据库的表结构转化为java的对象

初始化

初始化springboot应用 https://start.spring.io/

依赖spring web,spring data jpa,mysql driver

IDE导入生成的代码 open 选择pom.xml文件-openasproject(需要下载maven,并配置maven路径)

项目结构

  • scr-main-java —java相关文件
  • resources–前端静态文件或者配置文件
  • application.properties–全局的配置文件
  • test–
  • pom.xml—配置的依赖文件

启动应用

–BootDemoApplication运行main方法–访问http://localhost:8080/

报错 DataSource: ‘url’ attribute is not specified and no embedded datasource could be configured.因为引入了jpa需要对数据库进行访问。先注释掉依赖,再启动

创建controller

–所有的api都是由controller的方式提供的

Spring会将java对象通过Json序列化成为一个json字符串来返回。如果是自定义对象,属性要实现getset方法,不然没办法转化为接送字符串

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@RestController//注解用于将一个类标识为Spring MVC的Controller
public class TestController {

    @GetMapping("/hello")//配置访问的路径
    public String hello(){
        
        return "hello world";
    }
}
//hello world

@RestController//注解用于将一个类标识为Spring MVC的Controller
public class TestController {

    @GetMapping("/hello")//配置访问的路径
    public List<String> hello(){
        return List.of("hello","world");
    }
}
//返回的是接送数组["hello","world"]

rest api 规范

  • Http 动词

    • GET(SELECT):从服务器取出资源(一项或多项)。

    • POST(CREATE):在服务器新建一个资源。

    • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。

    • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。

    • DELETE(DELETE):从服务器删除资源。

创建数据库表

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
CREATE DATABASE test
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_general_ci;
  
CREATE TABLE student (
  id INT AUTO_INCREMENT PRIMARY KEY,# 自增主键
  name VARCHAR(50) NOT NULL,
  email VARCHAR(100) NOT NULL,
  age INT
);

配置数据库路径

application.properties

1
2
3
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456

data access层 dao层

数据访问层

maven标红-添加版本

将数据库中的数据映射到java对象中

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//将数据库中的数据映射到java对象中
@Entity
@Table(name = "student")
public class Student {

    @Id//自增的主键
    @Column(name = "id")//指定数据库字段
    @GeneratedValue(strategy = IDENTITY)//自增id,数据由数据库生成
    private long id;

    @Column(name = "name")
    private String name;

    @Column(name = "email")
    private String email;

    @Column(name = "age")
    private int age;
    
    //并生成getset方法
}


@Repository//标注在数据访问层(DAO层)的类,明确了这个类的主要职责是进行数据访问操作
//继承 JpaRepository<T, ID> 接口,自动获得了对 Student 实体类的数据访问能力
//为 StudentRespository 接口创建一个代理实现,这个实现会处理所有的数据访问操作
public interface StudentRespository extends JpaRepository<Student,Long> {//<对象,主键类型>
}

service层

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public interface StudentService {
	//关于getStudentById方法的具体实现,它并不在接口中定义。
    // 接口只声明了方法的签名(即方法的名称、参数列表和返回类型),而不提供方法的实现体。
    // 实现体(即方法的实际代码)需要在实现该接口的类中提供。
    Student getStudentById(long id);
}


@Service//加入到spring容器中,方便对应的对象注入
public class StudentServiceImpl implements StudentService{

    @Autowired
    private StudentRespository studentRespository;
    @Override
    public Student getStudentById(long id) {
        //通过id返回student对象
        return studentRespository.findById(id).orElseThrow(RuntimeException::new);
    }
}

contrller层

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@RestController
public class StudentController {

    //注入server层代码
    @Autowired
    private StudentService studentService;

    @GetMapping("student/{id}")//查询
    public Student getStudentById(@PathVariable long id){//路径变量,上面定义的id
        
		//返回json串
        return studentService.getStudentById(id);

    }
}

http://localhost:8080/student/1
{"id":1,"name":"eric","email":"abc@123.com","age":20}

dto层

controller直接将数据库对象返回,dto层用于返回展示给前端的对象,将数据库的student对象转化为需要展示的对象studentdto

并修改service、controller层需要传输的对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class StudentConverter {
    //将数据库中的student对象转为需要返回给前端的studentdto对象
    // 静态方法
    public static StudentDTO converterStudet(Student student){
        StudentDTO studentDTO =new StudentDTO();
        studentDTO.setId(student.getId());
        studentDTO.setName(student.getName());
        studentDTO.setEmail(student.getEmail());
        return studentDTO;
    }
}

Response类

接口规范标准需要返回一些信息,后端是否有报错返回正常,错误信息,作为后端结果的统一封装。用于前端通过一些字段去判断接口请求是否正常。加上错误信息和状态码信息

并修改controller层返回的对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Response <T>{
    private T data;//T 泛型
    private boolean success;//请求是否成功
    private String errorMsg;//错误信息

    //封装一些静态方法,更好调用
    //新建一个返回成功的response
    public static <K> Response<K> newSuccess(K data) {
        Response<K> response = new Response<>();
        response.setData(data);
        response.setSuccess(true);
        return response;
    }
    //返回失败的response
    public static Response<Void> newFail(String errorMsg) {
        Response<Void> response = new Response<>();
        response.setErrorMsg(errorMsg);
        response.setSuccess(false);
        return response;
    }
    //get。set方法
}

@GetMapping("student/{id}")//查询
    public Response<StudentDTO> getStudentById(@PathVariable long id){//路径变量,上面定义的id

        return Response.newSuccess(studentService.getStudentById(id));

    }

重新启动得到新的json串

1
2
3
4
5
6
7
8
9
{
  "data": {
    "id": 1,
    "name": "eric",
    "email": "abc@123.com"
  },
  "success": true,
  "errorMsg": null
}

上述便完整实现了get接口(查询接口)。

post-新增接口

controller层添加接口

1
2
3
4
5
6
7
@PostMapping("/student")
    //返回id即可
    public Response<Long> addNewStudent(@RequestBody StudentDTO studentDTO){//用于接收前端的json串,并反序列化为StudentDTO对象
        //一般会做一下校验
        return Response.newSuccess(studentService.addNewStudent(studentDTO));

    }

dao层实现findbyemail方法用于检查唯一性

1
2
3
	//jpa中findby按照字段的方法,按照约定的配置会自动根据去查询对应的数据,就不需要手写sql
    //在复杂场景下才需要手写
    List<Student> findByEmail(String email);

service层添加接口addNewStudent方法,并实现该接口,并将dto对象转为数据库student对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//service interface接口
Long addNewStudent(StudentDTO studentDTO);

	//impl具体实现
	@Override
    public Long addNewStudent(StudentDTO studentDTO) {
        //检查email的唯一性,没有findbyemail方法需要在Respository中实现
        List<Student> studentList = studentRespository.findByEmail(studentDTO.getEmail());
        if(!CollectionUtils.isEmpty(studentList)){
            //如果非空说明邮箱被占用,抛出异常
            throw new IllegalStateException("emil"+studentDTO.getEmail()+"has been taken");

        }
        //将接口的dto对象转为student对象
        Student student=studentRespository.save(StudentConverter.converterStudet(studentDTO));
        return student.getId();
    }

 	//studentDto转为student对象
    public static Student converterStudet(StudentDTO studentDTO){
        Student student =new Student();

        student.setName(studentDTO.getName());
        student.setEmail(studentDTO.getEmail());
        return student;
    }

利用postman去测试

重复email报错

但上述并没有上传age,修改为直接上传student对象,则包含age

delete–删除接口

controller层添加接口

1
2
3
4
	@DeleteMapping ("student/{id}")
    public void deleteStudentById(@PathVariable long id){
        studentService.deleteStudentById(id);
    }

service添加接口,并实现

1
2
3
4
5
6
7
8
9
void deleteStudentById(long id);

	@Override
    public void deleteStudentById(long id) {
        //判断id是否存在
        studentRespository.findById(id).orElseThrow(()->new IllegalArgumentException("id"+id+"doesn't exist"));
        studentRespository.deleteById(id);

    }

put–更新接口

1
2
3
4
5
6
7
8
	@PutMapping("/student/{id}")
    public Response<StudentDTO> updateStudentById(@PathVariable long id,
                                                  //更新email和age的时候,可能是非空,所以用requestparam而不是json去传递参数
                                                  @RequestParam(required=false) String name,
                                                  @RequestParam(required=false) String email
                                                  ){
        return Response.newSuccess(studentService.updateStudentById(id,name,email));
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
StudentDTO updateStudentById(long id, String name, String email);

	@Override
    //Spring 容器会在这个方法执行时启动一个事务,并在方法结束时根据方法的执行结果来提交或回滚事务。
    //如果在修改过程中发生异常或错误,那么事务可以回滚到修改之前的状态,从而保持数据的一致性
    @Transactional
    public StudentDTO updateStudentById(long id, String name, String email) {
        Student studentInDB=studentRespository.findById(id).orElseThrow(()->new IllegalArgumentException("id"+id+"doesn't exist"));

        //name空的话不更新,非空且不一致才更新
        if(StringUtils.hasLength(name)&& !studentInDB.getName().equals(name)){
            studentInDB.setName(name);
        }

        if(StringUtils.hasLength(email)&& !studentInDB.getEmail().equals(email)){
            studentInDB.setEmail(email);
        }
        Student student=studentRespository.save(studentInDB);

        //判断一下是否一致,是否还要新建,true,无须新建
//        System.out.println(student.equals(studentInDB));
        return StudentConverter.converterStudet(student);
    }

打包项目

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#打包
mvn clean install

cd D:\Java\project\boot-demo\boot-demo\target\ 
#启动项目
java -jar boot-demo-0.0.1-SNAPSHOT.jar

# 修改端口号
java -jar boot-demo-0.0.1-SNAPSHOT.jar --server.port=8081

MYSQL:包含jdbchttps://www.bilibili.com/video/BV15m421T7RQ/?spm_id_from=333.788&vd_source=ad42090d7d6fcdfc144126ae0e2884ac

jpa:https://www.bilibili.com/video/BV17m421M7CY/?spm_id_from=333.788&vd_source=ad42090d7d6fcdfc144126ae0e2884ac

mybatis:https://www.bilibili.com/video/BV18s421M7VV/?spm_id_from=333.788&vd_source=ad42090d7d6fcdfc144126ae0e2884ac

1
2
3
4
5
6
7
8
create table user(
id int AUTO_INCREMENT comment"自增主键" primary key,
username char(10)null comment"用户名",
passuord varchar(18)null COMMENT "密码",
nickname varchar(50)null COMMENT "昵称",
phone varchar(11)null comment "电话",
email varchar(50)null comment"邮箱")
comment"用户表"