SpringBoot案例
常见问题:
- 公司使用的框架(技术)没学过
- 公司的代码无处着手(顺着一条业务线)
- 前后端交互的过程不太理解
- 使用git不熟练
目标:
- 掌握springboot+mybatisplus框架的使用
- 了解前端框架vue (前端框架:angularjs、vue)
- 掌握前后端如何结合,更全面把握开发流程
- 在idea中使用git
我们通过一个对讲师模块进行增删改查的功能,去实现前端代码编写、后端代码编写、前后端整合,让大家对前后端分离有个整体性的认识,并掌握git的使用方式
一、讲师模块后端
准备数据:
create table teacher(
id varchar(19),# 主键
name varchar(20), # 讲师姓名
intro varchar(255), # 介绍
career text, # 职业成就
level int(10), # 水平
sort int(10) #排序
)
1、MyBatisPlus介绍
之前使用mybaits:
dao:TeacherMapper接口: 定义增删改查的方法
在xml配置文件中:编写对应的sql
代码的简化:像查询、修改、删除…基本的功能操作,能否有一个框架给咱们提供好了,用时直接使用即可!!
问题:mp功能上相比mybatis有没有增强?? 没有
类似:springboot 相对于spring体系中
官网:http://mp.baomidou.com/
为了方便书写,我们以后简称为mp,我们此处先对mp框架进行简单的了解,在后面讲师功能实现中再结合文档具体去讲解该框架。
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
愿景:我们的愿景是成为 MyBatis 最好的搭档
特性:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
2、工程搭建&环境准备
开发springboot项目:
- 引入坐标
- 配置文件的编写
- 包结构
- 测试一下
在Idea中创建springboot工程
2.1 引入坐标
<dependencies>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<!--lombok用来简化实体类:需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--开发者工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2.2 application.properties配置文件
# 服务端口
server.port=8001
# 服务名
spring.application.name=teacher_demo
# 环境设置:dev、test、prod
spring.profiles.active=dev
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=1234
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
2.3、启动工程进程测试
3、SpringBoot整合Swagger2
使用postman工具测试
在团队开发中,一个好的 API 文档不但可以减少大量的沟通成本,还可以帮助一位新人快速上手业务。传统的做法是由开发人员创建一份 RESTful API 文档来记录所有的接口细节,并在程序员之间代代相传。
这种做法存在以下几个问题:
第一:API 接口众多,细节复杂,需要考虑不同的HTTP请求类型、HTTP头部信息、HTTP请求内容等,想要高质量的完成这份文档需要耗费大量的精力;
第二:难以维护。随着需求的变更和项目的优化、推进,接口的细节在不断地演 变,接口描述文档也需要同步修订,可是文档和代码处于两个不同的媒介, 除非有严格的管理机制,否则很容易出现文档、接口不一致的情况
Swagger2 的出现就是为了从根本上解决上述问题。它作为一个规范和完整的框架,可以用于生成、描述、调用和可视化 RESTful 风格的 Web 服务:
1.接口文档在线自动生成,文档随接口变动实时更新,节省维护成本
2.支持在线接口测试,不依赖第三方工具
package com.ujiuye.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket webApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
.build();
}
private ApiInfo webApiInfo(){
return new ApiInfoBuilder()
.title("SpringBoot案例")
.description("本文档描述了讲师服务接口定义")
.version("1.0")
.contact(new Contact("db", "http://ujiuye.com", "222222244@qq.com"))
.build();
}
}
重启服务器查看接口:
http://localhost:8001/swagger-ui.html
4、讲师添加
如何使用mp做crud操作呢?
让TeacherMapper去继承BaseMapper:包括了常用的增删改查等基本操作
简化:
- 无需手动写crud方法
- 无需手动编写xml中的sql
主键策略:
(1) ID_WORKER
MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID
@TableId(type = IdType.ID_WORKER_STR)
private String id;
主键策略:
public enum IdType {
AUTO(0),
NONE(1),
INPUT(2),
ID_WORKER(3), //默认
UUID(4),
ID_WORKER_STR(5);
}
全局设置主键生成策略:
mybatis-plus.global-config.db-config.id-type=xx
5、统一返回结果集
项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更直观、轻松。
一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。
例如,我们的系统要求返回的基本数据格式如下:
列表: 查询所有讲师
{
"success": true,
"code": 20000,
"message": "成功",
"data": {
"items": [
{
"memberId": "1",
"mobile": "18911893513",
"createTime": "2018-05-15 01:20:52"
},{
"memberId": "1",
"mobile": "18911893513",
"createTime": "2018-05-15 01:20:52"
}
]
}
}
分页:
{
"success": true,
"code": 20000,
"message": "成功",
"data": {
"total": 17,
"rows": [
{
"memberId": "1",
"mobile": "18911893513",
"createTime": "2018-05-15 01:20:52"
}
]
}
}
没有返回数据:
{
"success": true,
"code": 20000,
"message": "成功",
"data": {“”:””,””:””}
}
失败:
{
"success": false,
"code": 20001,
"message": "失败",
"data": {}
}
因此,我们定义统一结果:
{
"success": 布尔, //响应是否成功
"code": 数字, //响应码
"message": 字符串, //返回消息
"data": HashMap //返回数据,放在键值对
}
定义类:
// 定义状态码
public interface ResultCode {
int OK = 20000; //成功
int ERROR = 20001;//失败
}
//定义返回结果类
@Data
public class Result {
private boolean success;
private Integer code;
private String message;
private Map<String,Object> data = new HashMap<String,Object>();
public static Result ok(){
Result r = new Result();
r.setSuccess(true);
r.setCode(ResultCode.OK);
r.setMessage("成功");
return r;
}
public static Result error(){
Result r = new Result();
r.setSuccess(false);
r.setCode(ResultCode.ERROR);
r.setMessage("失败");
return r;
}
public Result message(String message){
this.setMessage(message);
return this;
}
public Result code(Integer code){
this.setCode(code);
return this;
}
public Result data(String key, Object value){
this.data.put(key, value);
return this;
}
public Result data(Map<String, Object> map){
this.setData(map);
return this;
}
}
6、讲师修改
添加和修改的区别:
添加: Teacher中的信息,不需要id
修改:Teacher中的信息,需要id
6.1、根据id进行修改
6.2、自动填充
之前:teacher.setCreateTime(new Date())
项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作
-
数据库中添加自动填充字段
create_time和update_time
-
实体类上添加注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
- 实现元对象处理器接口
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
6.3、乐观锁
乐观锁概述:
乐观锁是丢失更新问题的解决方案
丢失更新问题:
对于一条数据,有两个事务要对这个条数据进行修改,第一个事务提交修改后,第二个事务也进行了事务提交修改,结果事务查看结果不是自己修改后的结果,明明修改了但是结果确不是自己修改的内容,这种现象就称为丢失更新问题。
主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
乐观锁实现方式:
-
取出记录时,获取当前version
-
更新时,带上这个version
-
执行更新时, set version = newVersion where version = oldVersion
-
如果version不对,就更新失败
实现:
(1) 数据库中添加version字段
(2) 实体类添加version属性并加@Version注解
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
(3) 元对象处理器接口添加version的insert默认值
this.setFieldValByName("version",1,metaObject);
(4) 在 TeacherConfig中注册 Bean
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
7、讲师删除
逻辑删除:
-
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
-
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
实现步骤:
(1)数据库中添加 deleted字段
(2)实体类添加deleted属性
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
(3)元对象处理器接口添加deleted的insert默认值
this.setFieldValByName("deleted",0,metaObject);
(4)application.properties 加入配置
此为默认值,如果你的默认值和mp默认的一样,该配置可无
Mp中默认0表示未被删除,可获取
1表示已被删除,无法获取
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
(5)在 TeacherConfig 中注册 Bean
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
8、讲师查询
8.1、查询所有
8.2、分页查询
引入分页插件
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
8.3、分页条件查询
Controller:
//分页条件查询
@PostMapping("{page}/{limit}")
public Result findByPage(@PathVariable Integer page,@PathVariable
Integer limit,@RequestBody TeacherQuery query){
Page<Teacher> pages = new Page<>(page, limit);
teacherService.pageQuery(pages,query);
//获取数据
List<Teacher> list = pages.getRecords();
//获取总记录数
long total = pages.getTotal();
System.out.println("总数:"+total);
return Result.ok().data("rows",list).data("total",total);
}
Service:
@Override
public void pageQuery(Page<Teacher> pageParam, TeacherQuery query){
QueryWrapper<Teacher> wrapper = new QueryWrapper<>();
wrapper.orderByAsc("sort");
//判断
if(query == null){
baseMapper.selectPage(pageParam,null);
return;
}
//获取值
String name = query.getName();
Integer level = query.getLevel();
String begin = query.getBegin();
String end = query.getEnd();
if(!StringUtils.isEmpty(name)){
wrapper.like("name",name);
}
if(!StringUtils.isEmpty(level)){
wrapper.eq("level",level);
}
if(!StringUtils.isEmpty(begin)){
wrapper.ge("gmt_create",begin);
}
if(!StringUtils.isEmpty(end)){
wrapper.le("gmt_create",end);
}
baseMapper.selectPage(pageParam,wrapper);
}
9、统一异常处理
面试题会涉及到
9.1、全局异常处理
我们想让异常结果也统一,并且在集中的地方处理系统的异常信息,那么需要统一异常处理
teacher_demo中创建统一异常处理类:
/**
* 统一异常处理类
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e){
e.printStackTrace();
return Result.error().message("执行出现了异常");
}
}
注解说明:
@ControllerAdvice ,很多初学者可能都没有听说过这个注解,实际上,这是一个非常有用的注解,顾名思义,这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能:
全局异常处理
全局数据绑定
全局数据预处理
灵活使用这三个功能,可以帮助我们简化很多工作,需要注意的是,这是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用.
@ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为NullpointerException,则数组越界异常就不会进到这个方法中来。
9.2、特定异常处理
//特定的异常 ArithmeticException
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public Result error(ArithmeticException e){
e.printStackTrace();
return Result.error().message("算术异常!!!");
}
9.3、自定义异常处理
// 自定义异常
@ExceptionHandler(ZiException.class)
@ResponseBody
public Result error(ZiException e){
e.printStackTrace();
return Result.error().code(e.getCode()).message(e.getMsg());
}
10、git在Idea中的使用
参考文档
二、讲师模块前端
重点:关注前端项目工程,看如何和后端进行交互的,以及了解以下两种技术:
介绍两种技术:
- vue 前端框架
- ElementUI
前端框架:angulajs
vue:
<div id="app">
{{ message }}
{{name}}
</div>
// js方式
doucument.getElementById("app").innerHTML = "内容体";
// jq方式
$("#app").html("内容体");
vue:
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
name:"lucy"
}
})
本文档详细介绍了使用SpringBoot和MyBatisPlus构建讲师管理模块的全过程,涵盖MyBatisPlus介绍、工程搭建、Swagger2整合、主键策略、统一返回结果集、乐观锁、逻辑删除、分页查询以及统一异常处理等内容,旨在帮助读者掌握前后端分离的开发流程和Git使用。
21万+

被折叠的 条评论
为什么被折叠?



