基于前面web开发的学习,我已经掌握了前端web开发(vue,html,js,css),后端web开发(Springboot基础,Mybatis),以及数据库(MySQL)相关的基础知识。接下来,我们要完成一个基于web开发的springboot综合案例。
通过此案例我们可以掌握前端、后端、数据库之间如何交互,同时也需要我们掌握通过接口文档开发服务端接口的能力。
案例说明:tlias智能学习辅助系统
因为该课程是javaweb后端,所以前端的内容会事先提供好,我们需要完成的事服务端接口的开发。
2.1.1需求分析
部门管理:
1.新增部门
2.编辑部门
3.删除部门
员工管理:
1.员工信息的条件分页查询
2.新增员工
3.编辑(修改)员工
4.删除员工
总的来说目前的功能就是完成数据库的增删改查。
2.1.2环境搭建
该项目总共分为三部分:前端、后端、数据库。前端发送请求,请求后端(服务端),服务端接收请求后操作数据库,操作处理完之后,服务端再给前端响应结果。
首先,准备数据库表
-- 部门管理
create table dept
(
id int unsigned primary key auto_increment comment '主键ID',
name varchar(10) not null unique comment '部门名称',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '部门表';
insert into dept (id, name, create_time, update_time)
values (1, '学工部', now(), now()),
(2, '教研部', now(), now()),
(3, '咨询部', now(), now()),
(4, '就业部', now(), now()),
(5, '人事部', now(), now());
-- 员工管理(带约束)
create table emp
(
id int unsigned primary key auto_increment comment 'ID',
username varchar(20) not null unique comment '用户名',
password varchar(32) default '123456' comment '密码',
name varchar(10) not null comment '姓名',
gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
image varchar(300) comment '图像',
job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
entrydate date comment '入职时间',
dept_id int unsigned comment '部门ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '员工表';
INSERT INTO emp
(id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time)
VALUES (1, 'jinyong', '123456', '金庸', 1, '1.jpg', 4, '2000-01-01', 2, now(), now()),
(2, 'zhangwuji', '123456', '张无忌', 1, '2.jpg', 2, '2015-01-01', 2, now(), now()),
(3, 'yangxiao', '123456', '杨逍', 1, '3.jpg', 2, '2008-05-01', 2, now(), now()),
(4, 'weiyixiao', '123456', '韦一笑', 1, '4.jpg', 2, '2007-01-01', 2, now(), now()),
(5, 'changyuchun', '123456', '常遇春', 1, '5.jpg', 2, '2012-12-05', 2, now(), now()),
(6, 'xiaozhao', '123456', '小昭', 2, '6.jpg', 3, '2013-09-05', 1, now(), now()),
(7, 'jixiaofu', '123456', '纪晓芙', 2, '7.jpg', 1, '2005-08-01', 1, now(), now()),
(8, 'zhouzhiruo', '123456', '周芷若', 2, '8.jpg', 1, '2014-11-09', 1, now(), now()),
(9, 'dingminjun', '123456', '丁敏君', 2, '9.jpg', 1, '2011-03-11', 1, now(), now()),
(10, 'zhaomin', '123456', '赵敏', 2, '10.jpg', 1, '2013-09-05', 1, now(), now()),
(11, 'luzhangke', '123456', '鹿杖客', 1, '11.jpg', 5, '2007-02-01', 3, now(), now()),
(12, 'hebiweng', '123456', '鹤笔翁', 1, '12.jpg', 5, '2008-08-18', 3, now(), now()),
(13, 'fangdongbai', '123456', '方东白', 1, '13.jpg', 5, '2012-11-01', 3, now(), now()),
(14, 'zhangsanfeng', '123456', '张三丰', 1, '14.jpg', 2, '2002-08-01', 2, now(), now()),
(15, 'yulianzhou', '123456', '俞莲舟', 1, '15.jpg', 2, '2011-05-01', 2, now(), now()),
(16, 'songyuanqiao', '123456', '宋远桥', 1, '16.jpg', 2, '2007-01-01', 2, now(), now()),
(17, 'chenyouliang', '123456', '陈友谅', 1, '17.jpg', NULL, '2015-03-21', NULL, now(), now());
然后,进行创建springboot工程以及导入相关依赖
最后框架如下所示
controller package·:存放的是控制类的代码
service package:存放的是业务层的接口以及实现类
mapper package:存放的是mapper接口
pojo package:存放的是实体类
当我们创建好了这些之后,我们需要通过使用注解将其交给IOC容器管理。Mapper使用@Mappper注解,service使用@Service注解,controller使用@RestController注解。
案例基于当前最主流的前后端分离模式进行开发。
前端开发人员和后端开发人员必须依照同一个接口文档进行开发。
2.2.1Restful风格
(REpresentational State Transfer),表述性状态转换,它是一种软件架构风格
传统风格
rest风格
2.2.2统一响应结果
前后端交互统一响应结果Result
package com.ittaotao.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code; //响应码,1代表成功;0代表失败
private String msg; //相应信息 描述字符串
private Object java; //返回的数据
//增删改 成功响应
public static Result success(){return new Result(1,"success",null);}
//查询 成功响应
public static Result success(Object data){ return new Result(1,"success",data);}
//失败响应
public static Result error(String msg) { return new Result(0,msg,null);}
}
tips:注解
@Data:使用该注解可以自动生成类的所有 Getter、Setter、equals、hashCode 和 toString 方法,省去了手动编写这些常用方法的工作。通常与其他注解(如@Getter和@Setter)一起使用。
@NoArgsConstructor:使用该注解可以自动生成一个无参的构造方法。在某些情况下,我们可能需要创建一个没有任何参数的对象,此时就可以使用这个注解。
@AllArgsConstructor:使用该注解可以自动生成一个包含所有参数的构造方法。在创建对象时,不需要逐个设置每个属性的值,而是直接将所有参数传递给构造方法即可。
2.2.3 开发流程
查看页面原型明确需求 --> 阅读接口文档 --> 思路分析 --> 接口开发 --> 接口测试 -->前后端联调
要求:查询全部数据(由于部门数据比较少,不考虑分页)
查询部门-思路
代码如下:
首先是控制类,controller会调用service的方法发送请求
package com.ittaotao.controller;
import com.ittaotao.pojo.Dept;
import com.ittaotao.pojo.Result;
import com.ittaotao.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Slf4j //此注解可以直接调用日志,不需要获取日志对象
@RestController
public class DeptController {
//获取日志对象
//private static Logger log = LoggerFactory.getLogger(DeptController.class);
@Autowired
private DeptService deptService;
//@RequestMapping(value = "/depts",method = RequestMethod.GET) //指定请求方式为GET
@GetMapping("/depts") //RequestMapping的衍生注解
public Result list() {
log.info("查询全部部门数据");
//调用service查询部门数据
List deptList = deptService.list();
return Result.success(deptList);
}
}
然后是service,service会调用mapper接口中的方法查询信息
package com.ittaotao.service.impl;
import com.ittaotao.mapper.DeptMapper;
import com.ittaotao.pojo.Dept;
import com.ittaotao.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public List list() {
return deptMapper.list();
}
}
最后是mapper,向数据库发送请求,查询全部部门数据,并将数据封装到list集合中
package com.ittaotao.mapper;
import com.ittaotao.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface DeptMapper {
/**
* 查询全部部门数据
* @return
*/
@Select("select * from dept")
List list();
}
最后我们捋一下这个过程:前端发送请求之后会请求到controller这个方法,controller方法中首先调用service去获取数据,在service中调用mapper接口中的方法来查询全部的部门信息,mapper接口就会向数据库中发送sql语句(查询全部的部门),并且把查询的部门信息封装在list集合当中,最终将集合的数据返回给service,service又返回给了controller,controller拿到返回回来的数据之后,最后将数据返回给前端。
最后返回数据显示在页面上,这点如果没有数据一定要检查你之前的是否拼错,端口号是否是正确的!
需求:开发一个接口。根据id删除当前部门的信息
删除部门 - 思路:
请求路径:/depts/{id}
请求方式:DELETE
通过注解@PathVariable获取参数,@DeleteMapping注解进行请求
这个就不附上代码了,跟上面的大差不差。不会的可以再去看下B站黑马里面老师的讲解
黑马-删除部门
需求:开发一个接口,添加部门信息
请求路径:/depts
请求方式:POST
接口描述:该接口用于添加部门数据
controller中:mapper方法上加上@PostMapping注解来限定当前接口必须以post请求,通过@RequestBody可以将一个json格式的数据封装到一个实体类中。
下面附上controller、service以及map的部分代码
/**
* 新增部门
* @return
*/
@PostMapping("/depts") //json格式的数据想封装到对象当中必须使用RequestBody注解
public Result add(@RequestBody Dept dept){
log.info("新增部门:{}",dept);
deptService.add(dept);
return Result.success();
}
@Override
public void add(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
deptMapper.insert(dept);
}
/**
* 新增部门信息
* @param dept
*/
@Insert("insert into dept (name, create_time, update_time) VALUES (#{name},#{createTime},#{updateTime})")
void insert(Dept dept);
小tips:@RequestMapping 抽取请求路径注解的公共部分
一个完整的请求路径,应该是类上的@RequestMapping的value属性+方法上的@RequestMapping的value属性
因为这部分老师没有讲,所以需要我们自己完成。不过有两部分,根据id查询、修改部门
所以需求如下:
1.开发一个接口,根据id查询部门
2,在开发一个接口,将查询到的部门修改成用户需要的部门。
根据id查询部门:
接口描述:该接口用于修改部门数据
请求路径:/depts/{id}
请求方式:GET
修改部门:
接口描述:该接口用于根据ID查询部门数据
请求路径:/depts
请求方式:PUT
下面附上我结合自身理解和网上资料完成的代码
/**
* 根据id查询部门
* @param id
* @return
*/
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id){
log.info("根据id查询部门:{}",id);
Dept dept = deptService.getById(id);
return Result.success(dept);
}
/**
* 修改部门
* @return
*/
@PutMapping
public Result update(@RequestBody Dept dept){
log.info("修改部门:{}",dept.getId());
deptService.update(dept);
return Result.success();
}
@Override
public Dept getById(Integer id) {
Dept dept = deptMapper.getById(id);
return dept;
}
@Override
public void update(Dept dept) {
dept.setUpdateTime(LocalDateTime.now());
deptMapper.update(dept);
}
/**
* 根据id查询部门
* @param id
* @return
*/
@Select("select * from dept where id = #{id}")
Dept getById(Integer id);
/**
* 修改部门
* @param dept
*/
@Update("update dept set name = (#{name}),update_time = #{updateTime} where id = (#{id})")
void update(Dept dept);
以上便是我们部门管理的所有内容了,下一篇我们继续分析后续内容!
文章如有问题还请各位评论区多多提出!