基于Maven+ SpringMVC+ MyBatis +Druid+MySql员工管理系统新手教程
前言
百度上搜这个还能跳出来个100+RMB的课程。这课有好多人看。我看了一下目录,发现大概比我的系统全面。但是,如果你只是要使用这些工具搭建一个员工管理系统,看我的就够了。虽然我只是个新手,但是我实现了,并且尽我所能讲清楚代码。
项目目标
我们搭建的员工管理系统是要有员工,部门和员工,部门的关系和对前三者在应用场景下的增删改查。
具体来说,对于员工和部门的增删改查是较简单的。只需注意增时要保证员工或部门不存在,删时保证员工或部门存在,改时保证员工或部门存在并且查时能用名字或id查找。对于两者关系的增删改查稍微变了些东西。查的时候通过部门名字查找所有该部门的员工信息,包括员工个数并且这些员工和部门要存在且id一致。
工具介绍
Maven是用来下各种各样jar包的。
SpringMVC
这是个设计框架。主要由模块层(Model),视图层(View)和控制层(controller)组成。
模块层封装了数据与进行数据进行处理的代码,是实际经行数据处理的地方,也是与数据库交互的地方。我的代码里包括Service,ServiceImpl和Mapper来处理数据。其实,在写这个项目时,大可不必分这么多层,会显得徒增代码量,但是这是个要养成的好习惯,至少要知道分层思想。
视图层负责将应用显示给用户和显示模型的状态。这主要是前端干的事,和我后端无瓜。我们的视图由Navicat解决。
控制层负责视图和模型之间的交互,把用户的请求发送到对应的模型上,并把模型的改变及时反应到视图上。
Mysql
这是个数据库。结构从上到下依次是数据库(database)和表(table)。
Mybatis
我们java程序中存储的数据是对象,怎么把对象转化成mysql中的表呢?靠的就是mybatis。
Druid
这是一个数据传输时的连接池。用这个是为了数据传输时加速与省消耗。以前每次连接数据库都要建立联系,就像每次回家,都要买辆车;如果用连接池,它会把我们数据传输时用的放进去,要用时从里面拿就行了,就像共享单车。
具体的点之后和代码一起补充。
我使用的是IDEA(编程),Postman(调用接口)和Navicat(mysql数据可视化)。
其中Navicat还提供直接用Mysql命令操作数据库的功能。菜单里点击Query,再点击newQuery,就能直接写Mysql语句来验证程序里的命令是否正确。非常方便。
开始制作
创建Mysql表
如果你是在本地玩,需要在本地先起一个Mysql服务。我下了个5开头的版本。
https://dev.mysql.com/downloads/file/?id=506120
在Navicat上连接Mysql。先创建个Mysql的数据库。记住你的数据库名,之后要用。
Pom.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<projectxmlns="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.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/><!--lookupparentfromrepository-->
</parent>
<groupId>com.vue</groupId>
<artifactId>mybatis_druid_mysql</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis_druid_mysql</name>
<description>mybatis_druid_mysql</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--web依赖,包含servlet,内置tomcat等-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--druid依赖包,配合springBoot项目使用-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.14</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
启动类
@Service
@SpringBootApplication
@MapperScan("/com.mybatis_druid_mysql.demo.Mapper")
publicclassDemoApplication{
publicstaticvoidmain(String[]args){
SpringApplication.run(DemoApplication.class,args);
}
}
与以往不同,多了个@MapperScan。它在用到java配置时登记Mybatis的Mapper接口。
Druid连接
就像上文提及,druid像共享单车。那么我们就要规定各项指标,比如有多少单车,每条车可以骑多久等等。
application.properties配置文件
server.port=18001
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=(1)
spring.datasource.druid.username=root
spring.datasource.druid.password=password
spring.datasource.druid.initial-size=5
spring.datasource.druid.max-active=20
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-wait=60000
spring.datasource.druid.timeBetweenEvictionRunsMillis=60000
spring.datasource.druid.minEvictableIdleTimeMillis=300000
spring.datasource.druid.maxPoolPreparedStatementPerConnectionSize=200
第一行是我们程序的端口。
(1) 这里是你的mysql数据库的url,形如:jdbc:mysql://127.0.0.1/db_example?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false
其中,db_example是数据库的名字。?后面代表一些参数。
第五行开始就是一些各种各样的druid设置。
怎么样让程序调用上这些配置呢?
packagecom.mybatis_druid_mysql.demo.Druid;
importcom.alibaba.druid.pool.DruidDataSource;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.boot.SpringBootConfiguration;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.PropertySource;
importorg.springframework.transaction.annotation.EnableTransactionManagement;
importjavax.sql.DataSource;
@SpringBootConfiguration
@PropertySource(value="classpath:/application.properties")
@EnableTransactionManagement
publicclassDruid{
@Value("${spring.datasource.druid.username}")
privateStringuserName;
@Value("${spring.datasource.druid.password}")
privateStringpassword;
@Value("${spring.datasource.druid.driver-class-name}")
privateStringdriverName;
@Value("${spring.datasource.druid.url}")
privateStringurl;
@Value("${spring.datasource.druid.initial-size}")
privateintinitialSize;
@Value("${spring.datasource.druid.max-active}")
privateintmaxActive;
@Value("${spring.datasource.druid.min-idle}")
privateintminIdle;
@Value("${spring.datasource.druid.max-wait}")
privateintmaxWait;
@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
privateinttimeBetweenEvictionRunsMillis;
@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
privateintminEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.maxPoolPreparedStatementPerConnectionSize}")
privateintmaxPoolPreparedStatementPerConnectionSize;
@Bean(name="datasource")
publicDataSourcedataSource(){//由druid-spring-boot-starter实现springboot提供的datasource接口
DruidDataSourcedataSource=null;
try{
dataSource=newDruidDataSource();
dataSource.setUsername(userName);
dataSource.setPassword(password);
dataSource.setUrl(url);
dataSource.setDriverClassName(driverName);
dataSource.setInitialSize(initialSize);
dataSource.setMaxActive(maxActive);
dataSource.setMinIdle(minIdle);
dataSource.setMaxWait(maxWait);
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
}catch(Exceptione){
e.printStackTrace();
}
returndataSource;
}
}
@SpringBootConfiguration注释是一个类级别的注释,它指示此类提供了应用程序配置。
@PropertySource(value = "classpath:/application.properties")注释是一个读取properties配置文件属性的注释,塔指示了配置文件地址。
@EnableTransactionManagement注释是一个事务管理注解。
@Value注释是一个从属性源取值的注释,它后面写注释源的名称。
上面代码设置了dataSource。之后就会交给druid-spring-boot-starter这个依赖处理。
这样,Druid就连接完成啦!
Entity创建
实体(Entity)定义了我们数据的基本结构。比如,我们这里要做3张表:员工信息表,部门信息表和员工部门关系表。
Employee
@Entity(name="employee")
@Data
publicclassEmployee{
@Id
Longid;
Stringname;
Stringsex;
Stringaddress;
}
@Entity(name = "employee")注释说明这是一个实体,而且名字叫employee。
@Data注释说明这是一个数据,它代替了普通的getter和setter。
@Id注释说明这是这个实体的主键(primary key)。
Department
@Entity(name="department")
@Data
publicclassDepartment{
@Id
Longdepartment_id;
Stringdepartment_name;
}
Connection
@Entity(name="connection")
@Data
publicclassConnection{
@Id
Longconnection_id;
Longdepartment_id;
Longemployee_id;
Stringemployee_name;
Stringdepartment_name;
}
数据处理
从端口调用接口到实现数据的增上改查(CRUD),是怎么实现的呢?
我的总共个分为这么几层:Controller->Service->ServiceImpl->Mapper。正规一点还要加上一层Dao层。
Controller
@RestController
@RequestMapping("/jerry")
@Slf4j
publicclassController{
@Autowired
privateServiceservice;
@PostMapping(value="/insertEmployee",produces=MediaType.APPLICATION_JSON_UTF8_VALUE,
consumes=MediaType.APPLICATION_JSON_UTF8_VALUE)
publicEmployeeinsertEmployee(@RequestBodyEmployeeemployee){
if(service.countEmployee(employee)==0)
service.insertEmployee(employee);
returnemployee;
}
@DeleteMapping("/deleteEmployee")
publicStringdeleteEmployee(@RequestParamStringid){
service.deleteEmployee(id);
return"deleted";
}
@PutMapping(value="/updateEmployee",produces=MediaType.APPLICATION_JSON_UTF8_VALUE,
consumes=MediaType.APPLICATION_JSON_UTF8_VALUE)
publicEmployeeupdateEmployee(@RequestParamLongid,@RequestBodyEmployeeemployee){
employee.setId(id);
service.updateEmployee(employee);
log.info("result: {}",employee);//打印日志
returnemployee;
}
@GetMapping(value="/searchEmployee",produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
publicEmployeesearchEmployee(@RequestParam("id")Stringid){
returnservice.searchEmployee(id);
}
@PostMapping(value="/addDepartment",produces=MediaType.APPLICATION_JSON_UTF8_VALUE,
consumes=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
publicDepartmentaddDepartment(@RequestBodyDepartmentdepartment){
if(service.countDepartment(department)==0)
service.addDepartment(department);
returndepartment;
}
@DeleteMapping("/deleteDepartment")
@ResponseBody
publicStringdeleteDepartment(@RequestParamLongdepartment_id){
service.deleteDepartment(department_id);
return"deleted";
}
@GetMapping(value="/searchDepartment",produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
publicDepartmentsearchDepartment(@RequestParam("department_id")Stringdepartment_id){
log.info("result: {}",service.searchDepartment(department_id));//打印日志
Departmentdepartment=service.searchDepartment(department_id);
returnservice.searchDepartment(department_id);
}
@PutMapping(value="/updateDepartment",produces=MediaType.APPLICATION_JSON_UTF8_VALUE,
consumes=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
publicDepartmentupdateDepartment(@RequestParamLongdepartment_id,@RequestBodyDepartmentdepartment){
department.setDepartment_id(department_id);
service.updateDepartment(department);
returndepartment;
}
@RequestMapping(value="/addConnection",produces=MediaType.APPLICATION_JSON_UTF8_VALUE,
consumes=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
publicConnectionaddConnection(@RequestBodyConnectionconnection){
if(service.countConnection(connection)==0&&(service.employeeExistAndIdCorrect(connection)==1
&&(service.departmentExistAndIdCorrect(connection)==1)))
service.addConnection(connection);
returnconnection;
}
@RequestMapping("/deleteConnection")
@ResponseBody
publicStringdeleteConnection(Longconnection_id){
service.deleteConnection(connection_id);
return"deleted";
}
@RequestMapping("/deleteEmployeeFromDepartment")
@ResponseBody
publicStringdeleteEmployeeFromDepartment(@RequestParam("employee_id")Longemployee_id,@RequestParam("department_id")Longdepartment_id){
service.deleteEmployeeFromDepartment(employee_id,department_id);
return"deleted";
}
@RequestMapping("/updateConnection")
@ResponseBody
publicStringupdateConnection(@RequestBodyConnectionconnection,@RequestParamLongconnection_id){
connection.setConnection_id(connection_id);
service.updateConnection(connection);
return"updated";
}
@RequestMapping("/searchEmployeeFromDepartment")
@ResponseBody
publicList<Connection>searchEmployeeFromDepartment(Stringdepartment_name){
returnservice.searchEmployeeFromDepartment(department_name);
}
@RequestMapping("/searchDepartmentFromEmployee")
@ResponseBody
publicList<Connection>searchDepartmentFromEmployee(Stringemployee_name){
returnservice.searchDepartmentFromEmployee(employee_name);
}
@RequestMapping("/countEmployeeFromDepartment")
@ResponseBody
publicLongcountEmployeeFromDepartment(Stringdepartment_name){
returnservice.countEmployeeFromDepartment(department_name);
}
}
@RestController注释是一个连接了两种其他注释的注释,他们分别是@Controller和@ResponseBody,前者告诉系统这是个控制类,并且暗含@Component,能被系统扫描到;后者告诉系统这里返回的数据是以网络反应体(web response body)展示的,不是普通的返回数据。
@RequestMapping("/jerry")注释是一个引导网络请求到请求处理类的注释,它定义了调用接口时的路径。
@Slf4j注释是一个来自lombok依赖的注释,他能打印日志。
@Autowired注释是一个自动导航的注释,它能把@Component注释下的类纳为己用。
@PostMapping注释是@RequestMapping的一种,它要求请求时用Post方法调用。这种方法通常用在增删改查中的增。
@DeleteMapping注释是@RequestMapping的一种,它要求请求时用Delete方法调用。这种方法通常用在增删改查中的删。
@PutMapping注释是@RequestMapping的一种,它要求请求时用Put方法调用。这种方法通常用在增删改查中的改。
@GetMapping注释是@RequestMapping的一种,它要求请求时用Get方法调用。这种方法通常用在增删改查中的查。
以上四者都能定义请求调用时的路径和输入输出的数据形式。比如Json形式,方便观察。
我代码中前面还是挺规范,到后面全是@RequestMapping,这不好。
@RequestParam和@RequestBody都是定义网络请求参数名称,前者参数是普通参数(parameter),比如String或Long;后者参数是一个类。
我代码中前面还是挺规范,到后面全都漏了,这不好。
你可能注意到了,我的所有实体的属性都是小写,单词之间由下划线分开。比如department_name。这是因为如果不这么做,Mysql会自动把这些属性转化成表中的Title时,自动变小写,单词用下划线分开。按理说分开就分开,但是我试了一下,会引起一个我搞不懂的bug。于是就向Mysql妥协。
Service
这就是个接口类,由ServiceImpl实现。
@org.springframework.stereotype.Service
publicinterfaceService{
publicvoidinsertEmployee(Employeeemployee);
publicLongcountEmployee(Employeeemployee);
publicvoiddeleteEmployee(Stringid);
publicvoidupdateEmployee(Employeeemployee);
publicEmployeesearchEmployee(Stringid);
publicvoidaddDepartment(Departmentdepartment);
publicLongcountDepartment(Departmentdepartment);
publicvoiddeleteDepartment(Longdepartment_id);
publicDepartmentsearchDepartment(Stringdepartment_id);
publicvoidupdateDepartment(Departmentdepartment);
publicvoidaddConnection(Connectionconnection);
publicLongcountConnection(Connectionconnection);
publicvoiddeleteConnection(Longconnection_id);
publicvoidupdateConnection(Connectionconnection);
publicList<Connection>searchEmployeeFromDepartment(Stringdepartment_id);
publicList<Connection>searchDepartmentFromEmployee(Stringemployee_name);
publicLongcountEmployeeFromDepartment(Stringdepartment_name);
publicvoiddeleteEmployeeFromDepartment(Longemployee_id,Longdepartment_id);
publicLongemployeeExistAndIdCorrect(@Param("connection")Connectionconnection);
publicLongdepartmentExistAndIdCorrect(@Param("connection")Connectionconnection);
}
@Service注释是一个指明该类是个独立服务层的注释,它是@Component的一种,能被扫描到。
这里它变成@org.springframework.stereotype.Service这么长,是因为我的类名也是Service,系统为了区分,就写长了。
ServiceImpl
@org.springframework.stereotype.Service
@Transactional
publicclassServiceImplimplementsService{
@Autowired
privateMappermapper;
publicvoidinsertEmployee(Employeeemployee){
mapper.insertEmployee(employee);
}
publicLongcountEmployee(Employeeemployee){
returnmapper.countEmployee(employee);
}
publicvoiddeleteEmployee(Stringid){
mapper.deleteEmployee(id);
}
publicvoidupdateEmployee(Employeeemployee){
mapper.updateEmployee(employee);
}
publicEmployeesearchEmployee(Stringid){
returnmapper.searchEmployee(id);
}
publicvoidaddDepartment(Departmentdepartment){
mapper.addDepartment(department);
}
publicLongcountDepartment(Departmentdepartment){returnmapper.countDepartment(department);}
publicvoiddeleteDepartment(Longdepartment_id){
mapper.deleteDepartment(department_id);
}
publicDepartmentsearchDepartment(Stringdepartment_id){
returnmapper.searchDepartment(department_id);
}
publicvoidupdateDepartment(Departmentdepartment){
mapper.updateDepartment(department);
}
publicvoidaddConnection(Connectionconnection){
mapper.addConnection(connection);
}
publicLongcountConnection(Connectionconnection){returnmapper.countConnection(connection);}
publicvoiddeleteConnection(Longconnection_id){
mapper.deleteConnection(connection_id);
}
publicvoidupdateConnection(Connectionconnection){
mapper.updateConnection(connection);
}
publicList<Connection>searchDepartmentFromEmployee(Stringemployee_name){
returnmapper.searchDepartmentFromEmployee(employee_name);
}
publicList<Connection>searchEmployeeFromDepartment(Stringdepartment_name){
returnmapper.searchEmployeeFromDepartment(department_name);
}
publicLongcountEmployeeFromDepartment(Stringdepartment_name){
returnmapper.countEmployeeFromDepartment(department_name);
}
publicvoiddeleteEmployeeFromDepartment(Longemployee_id,Longdepartment_id){
mapper.deleteEmployeeFromDepartment(employee_id,department_id);
}
publicLongemployeeExistAndIdCorrect(@Param("connection")Connectionconnection){
returnmapper.employeeExistAndIdCorrect(connection);
}
publicLongdepartmentExistAndIdCorrect(@Param("connection")Connectionconnection){
returnmapper.departmentExistAndIdCorrect(connection);
}
}
@Transactional注释是一个为独立方法或一个类的转换属性的注释。
Mapper
使用Mysql命令,用于将对象与Mysql里的表打交道。
@org.apache.ibatis.annotations.Mapper
publicinterfaceMapper{
@Insert("insert into employee(name,sex,address) values(#{name},#{sex},#{address})")
@Options(useGeneratedKeys=true,keyColumn="id")//展示id
voidinsertEmployee(Employeeemployee);
@Select("select count(*) from employee where name = #{name}")
LongcountEmployee(Employeeemployee);
@Delete("delete from employee where id = #{id}")
voiddeleteEmployee(@Param("id")Stringid);
@Update("update employee set name = #{name},sex = #{sex},address = #{address} where id = #{id}")
@Options(useGeneratedKeys=true,keyColumn="id")
voidupdateEmployee(@Param("employee")Employeeemployee);
@Select("select * from employee where id = #{id}")
@Options(useGeneratedKeys=true,keyColumn="id")
EmployeesearchEmployee(@Param("id")Stringid);
@Insert("insert into department(department_name) values(#{department_name})")
@Options(useGeneratedKeys=true,keyProperty="department_id")
voidaddDepartment(Departmentdepartment);
@Select("select count(*) from department where department_name = #{department_name}")
LongcountDepartment(Departmentdepartment);
@Delete("delete from department where department_id = #{department_id}")
voiddeleteDepartment(@Param("department_id")Longdepartment_id);
@Select("select * from department where department_id = #{department_id}")
@Options(useGeneratedKeys=true,keyProperty="department_id")
DepartmentsearchDepartment(@Param("department_id")Stringdepartment_id);
@Update("update department set department_id = #{department_id}, department_name = #{department_name} where department_id = #{department_id}")
@Options(useGeneratedKeys=true,keyColumn="department_id",keyProperty="department_id")
voidupdateDepartment(@Param("department")Departmentdepartment);
@Insert("insert into connection(department_id,department_name,employee_id,employee_name)values(#{department_id},#{department_name},#{employee_id},#{employee_name})")
@Options(useGeneratedKeys=true,keyColumn="connection_id",keyProperty="connection_id")
voidaddConnection(Connectionconnection);
@Select("select count(*) from connection where department_name = #{department_name} and employee_name = #{employee_name}")
LongcountConnection(Connectionconnection);
@Delete("delete from connection where connection_id = #{connection_id}")
voiddeleteConnection(Longconnection_id);
@Delete("delete from connection where employee_id = #{employeeId} and department_id = #{department_id}")
voiddeleteEmployeeFromDepartment(@Param("employeeId")Longemployee_id,
@Param("department_id")Longdepartment_id);
@Update("update connection set employee_id = #{employee_id}, employee_id = #{employee_id}, department_id = #{department_id} , employee_name = #{employee_name} where connection_id = #{connection_id}")
@Options(useGeneratedKeys=true,keyColumn="connection_id",keyProperty="connection_id")
voidupdateConnection(Connectionconnection);
@Select("select * from connection where employee_name = #{employee_name}")
@Options(useGeneratedKeys=true,keyColumn="employee_name",keyProperty="employee_name")
List<Connection>searchDepartmentFromEmployee(Stringemployee_name);
@Select("select * from connection where department_name = #{department_name}")
@Options(useGeneratedKeys=true,keyColumn="department_name",keyProperty="department_name")
List<Connection>searchEmployeeFromDepartment(@Param("department_name")Stringdepartment_name);
@Select("select count(*) from connection where department_name = #{department_name}")
publicLongcountEmployeeFromDepartment(@Param("department_name")Stringdepartment_name);
@Select("select count(*) from employee where name = #{employee_name} and id = #{employee_id}")
publicLongemployeeExistAndIdCorrect(@Param("connection")Connectionconnection);
@Select("select count(*) from department where department_name = #{department_name} and department_id = #{department_id}")
publicLongdepartmentExistAndIdCorrect(@Param("connection")Connectionconnection);
}
以上括号内的语句就是Mysql命令,其相关意思网上多的很,我就不解释了。就算是新人也能通过字面意思与上文结合,猜知大概。
Navicat使用
其实这里应该与代码测试穿插着用,上文到这不是真正开始制作的顺序。
如果ENtity内写了表名,那么在最开始船舰的数据库下就会自动生成相应的表,以及该表的第一列;若没有,则手动生成。
在每次调用接口测试代码时,它会要求每张表都要有自增主键。于是,我们要右键表名,选择“Design Table”,选择相应主键,勾选自增(Auto-Increment)。
它刷新时间意不要用右键选择刷新,而要用底部的刷新键,或是重启Navicat。
注意事项
除了上文所提及的各种事项,我再整理一些修理bug的总结。
各种依赖包内的类别引用错了,很多都是同名的,注意选择你想要的。假如你和我一样对理论不熟悉,就要点开(“ctrl" + 左键)这些类一看究竟。有时他甚至不会一下显示这些同名的类,坑的我好惨。
写代码要规范,养成好习惯。有许多现在看来可写可不写的,那是因为我们程序功能简单。以后功能复杂起来,再不写规范,那就是一坨屎,不仅没人想看,自己过几天也不想看。