目录
1、后端实现
1.2、到Setting中修改Maven配置
1.3、打开项目的pom.xml文件,修改版本为2.5.13
1.4、Springboot pom.xml完整的配置文件
创建完Springboot项目后,接着在idea中配置Maven,接下来直接复制以上pom.xml文件内容到项目的pom.xml
1.6、配置application.properties
1.7、利用Mybatis-plue逆向工程生成单表
1.8、配置swagger-ui用于接口测试
1.9、配置mybatis-plus分页插件
1.10、配置mybatis-plus公共字段插入
1.11、配置工具类
1.12、编写增、删、改、查接口
1.13、前端传入id错误导致后台无法删除
2、前端实现
2.1、用vscode创建一个前端项目
2.2、在vuecrud下创建crud.html
2.3、在html中用相关的js,css等文件
2.4、在crud.html中引入相应文件
2.5、创建一个div,id=app,创建一个vue对象
2.6、分页查询数据展示
2.6.1、定义变量
2.6.2、编写请求分页查询的函数
2.6.3、编写显示页面
2.7、删除数据
2.8、新增数据
2.8.1、在data添加红色:
2.8.2、编写请求添加的函数
2.8.3、新增页面显示
2.9、修改数据
2.9.1、编写请求添加的函数
3、运行显示页面
1、后端实现
用到的依赖:Springboot,Mybatis-plus,lombok,mysql驱动
1.1、利用IDEA2021创建一个Springboot项目
注意:Name(项目名称) location(项目在磁盘上的位置)
Type(选Maven)Group(一般是把公司或者组织的域名倒过来)
Lombok用于实体类的get,set以及构造器的自动生成,而且@Slf4j也
在Lombok中,比如说log.info()打印相关变量
Mysql依赖
MySQL :: MySQL Connector/J 8.0 Developer Guide :: 4.2 Installing Connector/J Using Maven
xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.5.13version>
<relativePath/>
parent>
<groupId>cn.com.bubagroupId>
<artifactId>vuecrudartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>vuecrudname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>11java.version>
<mysql.version>8.0.21mysql.version>
<mybatis-plus.version>3.4.2mybatis-plus.version>
<mybatis-plus-generator.version>3.4.1mybatis-plus-generator.version>
<velocity-engine-core.version>2.3velocity-engine-core.version>
<swagger.version>2.7.0swagger.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>${mybatis-plus.version}version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>${mybatis-plus-generator.version}version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocity-engine-coreartifactId>
<version>${velocity-engine-core.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>${swagger.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>${swagger.version}version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
project>
新建数据库
DROP TABLE IF EXISTS `hospital_set`;
CREATE TABLE `hospital_set` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`hosname` varchar(100) DEFAULT NULL COMMENT '医院名称',
`hoscode` varchar(30) DEFAULT NULL COMMENT '医院编号',
`api_url` varchar(100) DEFAULT NULL COMMENT 'api基础路径',
`sign_key` varchar(50) DEFAULT NULL COMMENT '签名秘钥',
`contacts_name` varchar(20) DEFAULT NULL COMMENT '联系人',
`contacts_phone` varchar(11) DEFAULT NULL COMMENT '联系人手机',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '状态',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '逻辑删除(1:已删除,0:未删除)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_hoscode` (`hoscode`)
) ENGINE=InnoDB AUTO_INCREMENT=39 DEFAULT CHARSET=utf8mb3 COMMENT='医院设置表';
-- ----------------------------
-- Records of hospital_set
-- ----------------------------
INSERT INTO `hospital_set` VALUES ('1', '*东方医院', '00012', '/api/tiantan', '122', '', null, '0', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '1');
INSERT INTO `hospital_set` VALUES ('2', '*东方医院', '00015', '/api/east', '122', '', '', '0', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '1');
INSERT INTO `hospital_set` VALUES ('3', '*空军医院', '00016', '/api/airforce', '122', '', '', '0', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '0');
INSERT INTO `hospital_set` VALUES ('4', '*陆军医院', '00017', '/api/army', '122', '', '', '0', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '0');
INSERT INTO `hospital_set` VALUES ('5', '*海军医院', '00019', '/api/navy', '122', '', '', '0', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '1');
复制到application.properties里
#服务器端口号
server.port=8080
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3307/crud?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=111111·
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
mybatis-plus.configuration.map-underscore-to-camel-case=true
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#主键生成策略:雪花算法
mybatis-plus.global-config.db-config.id-type=ASSIGN_ID
将这个文件放到和启动类同一包下(红色字体要修改的内容)
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CodeGenerator {
/**
*
* 读取控制台内容
*
如果成功生成相应的包及接口和类后,找到mapper包下的接口,在其加上@Mapper
新建一个config包,和controller包同级
将Swagger2Config文件放到config包中,内容如下(需要修改的字体为红色)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
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;
/**
* Swagger2配置信息
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
//apiInfo指定测试文档基本信息,这部分将在页面展示
.apiInfo(apiInfo())
.select()
//apis() 控制哪些接口暴露给swagger,
// RequestHandlerSelectors.any() 所有都暴露
// RequestHandlerSelectors.basePackage("com.info.*") 指定包位置
.apis(RequestHandlerSelectors.basePackage("cn.com.buba"))
.paths(PathSelectors.any())
.build();
}
//基本信息,页面展示
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("增删改查")
.description("springboot增删改查")
.version("1.0")
.contact(new Contact("xxx", "http://www.baidu.com", "[email protected]"))
.build();
}
}
启动项目输入网址http://localhost:8080/swagger-ui.html
看到如下网址表示swagger-ui配置成功
将MybatisPlusConfig.java放到config包里文件内容如下
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
log.info("分页插件......");
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
将MyConfig.java放到config包里文件内容如下
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
@Configuration
@Slf4j
public class MyConfig {
@Bean
public MetaObjectHandler metaObjectHandler(){
return new MetaObjectHandler() {
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始处理 insert方式 公共字段");
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
// metaObject.setValue("createUser", BaseContext.getCurrentId());
// metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
@Override
public void updateFill(MetaObject metaObject) {
//验证LoginFilter 的doFilter
// MyMetaObjectHandler的updateFill
// EmployeeController的update方法使用同一线程
Long sameId = Thread.currentThread().getId();
log.info("doFilter updateFill update sameId = {}", sameId);
log.info("开始处理 update方式 公共字段");
metaObject.setValue("updateTime", LocalDateTime.now());
// metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
};
}
}
因为mybatis-plus帮我们自动生成了mapper,service,serviceImpl在这个过程要检查mapper及serviceImpl上有@Mapper,@Service
接下来我们要在Controller上编写(此接口不是interface)
创建一个包util,和controller同级,用来存放工具类
将ResultCodeEnum.java和Result.java放到util包中,用于统一返回结果
ResultCodeEnum.java:
import lombok.Getter;
/**
* 统一返回结果状态信息类
*/
@Getter
public enum ResultCodeEnum {
SUCCESS(200,"成功"),
FAIL(201, "失败"),
PARAM_ERROR( 202, "参数不正确"),
SERVICE_ERROR(203, "服务异常"),
DATA_ERROR(204, "数据异常"),
DATA_UPDATE_ERROR(205, "数据版本异常"),
LOGIN_AUTH(208, "未登陆"),
PERMISSION(209, "没有权限"),
CODE_ERROR(210, "验证码错误"),
// LOGIN_MOBLE_ERROR(211, "账号不正确"),
LOGIN_DISABLED_ERROR(212, "改用户已被禁用"),
REGISTER_MOBLE_ERROR(213, "手机号已被使用"),
LOGIN_AURH(214, "需要登录"),
LOGIN_ACL(215, "没有权限"),
URL_ENCODE_ERROR( 216, "URL编码失败"),
ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回调请求"),
FETCH_ACCESSTOKEN_FAILD( 218, "获取accessToken失败"),
FETCH_USERINFO_ERROR( 219, "获取用户信息失败"),
//LOGIN_ERROR( 23005, "登录失败"),
PAY_RUN(220, "支付中"),
CANCEL_ORDER_FAIL(225, "取消订单失败"),
CANCEL_ORDER_NO(225, "不能取消预约"),
SIGN_ERROR(300, "签名错误"),
;
private Integer code;
private String message;
private ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
Result.java:
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 全局统一返回结果类
*/
@Data
@ApiModel(value = "全局统一返回结果")
public class Result<T> {
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回数据")
private T data;
public Result(){}
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<T>();
if (data != null)
result.setData(data);
return result;
}
public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
Result<T> result = build(body);
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
return result;
}
public static <T> Result<T> build(Integer code, String message) {
Result<T> result = build(null);
result.setCode(code);
result.setMessage(message);
return result;
}
public static<T> Result<T> ok(){
return Result.ok(null);
}
/**
* 操作成功
* @param data
* @param
* @return
*/
public static<T> Result<T> ok(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.SUCCESS);
}
public static<T> Result<T> fail(){
return Result.fail(null);
}
/**
* 操作失败
* @param data
* @param
* @return
*/
public static<T> Result<T> fail(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.FAIL);
}
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
public boolean isOk() {
if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
return true;
}
return false;
}
}
在实体类Hospital-set的id上添加注解
@JsonFormat(shape = JsonFormat.Shape.STRING)
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
前端页面显示的id
数据库显示的id
用到的技术:es6, Html5, vue2, axios, elementUi, css
前后端分离,跨域
在磁盘上新建一个文件夹vuecrud
利用vscode打开vuecrud文件夹
将plugins,style放在2.1创建的vuecrud下面
引入css
引入js
new Vue({
el:"#app",
data(){
return{
}
},
created(){
},
methods:{
}
})
在vue对象的data return里面定义
data() {
return {
tablelist: [], //返回当前页的数据,
page: 1, //当前页,默认值为第一页
pageSize: 5, //每页5条数据
total: 0, //总条数
}
},
在methods里编写
//请求分页数据
getPage(page, pageSize) {
axios.get(`http://localhost:8080/admin/hosp/hospitalSet`+
`/getPage/${page}/${pageSize}`)
.then(res => {
console.log(res)
this.tablelist = res.data.data.records
this.total = res.data.data.total
})
},
在created编写
this.getPage(this.page, this.pageSize)
在div添加
修改
删除
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange">
在methods添加
//根据id删除
deleteHandle(id) {
this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.get(`http://localhost:8080/admin/hosp/hospitalSet/removeById?id=${id}`)
.then(res => {
if (res.data.code == 200) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getPage(this.page, this.pageSize)
} else {
this.$message({
type: 'error',
message: '删除失败!'
});
this.getPage(this.page, this.pageSize)
}
})
})
},
data() {
return {
tablelist: [], //返回当前页的数据,
page: 1, //当前页,默认值为第一页
pageSize: 5, //每页5条数据
total: 0, //总条数
action: '',//新增、修改共用一个dialog
rowObj: {},//scope.row
form: {
hosname: '',
hoscode: '',
apiUrl: '',
contactsName: '',
contactsPhone: '',
title: '新增医院信息',
dialogFormVisible: false,
},
formLabelWidth: '120px',
}
},
在methods编写
addClass() {
this.form.title = '添加医院设置信息'
this.action = 'add'
this.form.dialogFormVisible = true
},
// 关闭弹窗
handleClose() {
this.resetForm()
this.form.dialogFormVisible = false
},
//根据动作类型决定是否增加或编辑
submitForm() {
if (this.action == "add") {
this.hospSetAdd(this.form)
} else {
this.hospSetEdit(this.form)
}
},
//发送新增请求
hospSetAdd(form) {
console.info(form)
axios.post(`http://127.0.0.1:8080/admin/hosp/hospitalSet/save`,
{
hosname: form.hosname,
hoscode: form.hoscode,
apiUrl: form.apiUrl,
contactsName: form.contactsName,
contactsPhone: form.contactsPhone
})
.then(res => {
this.dialogFormVisible = false
this.$message({
message: '新增医院设置信息成功!',
type: 'success'
});
this.resetForm()
this.getPage(this.page, this.pageSize)
console.info(res)
})
.catch(error => {
console.info(error)
})
},
在div编写:
@click="submitForm('go')"> 保存并继续添加
在methods编写:
//编辑时回显数据
editHandle(dat) {
this.form.title = '修改医院设置信息'
this.action = 'edit'
this.form.name = dat.name
this.rowObj = dat
this.form.hosname = dat.hosname
this.form.hoscode = dat.hoscode
this.form.apiUrl = dat.apiUrl
this.form.contactsName = dat.contactsName
this.form.contactsPhone = dat.contactsPhone
this.form.dialogFormVisible = true
},
//发送update请求
hospSetEdit(form) {
console.info(form)
axios.post(`http://127.0.0.1:8080/admin/hosp/hospitalSet/updateHosp`,
{
id: this.rowObj.id,
hosname: form.hosname,
hoscode: form.hoscode,
apiUrl: form.apiUrl,
contactsName: form.contactsName,
contactsPhone: form.contactsPhone
})
.then(res => {
this.dialogFormVisible = false
this.$message({
message: '修改医院设置信息成功!',
type: 'success'
});
this.handleClose()
this.getPage(this.page, this.pageSize)
// console.info(res)
})
.catch(error => {
console.info(error)
})
},
//重置表单
resetForm() {
this.form.hosname = ""
this.form.hoscode = ""
this.form.apiUrl = ""
this.form.contactsName = ""
this.form.contactsPhone = ""
},