1. 第四阶段课程安排
-
编程技术清单:
-
Mybatis框架相关
-
Spring Boot框架相关
-
Spring MVC框架相关 / Spring框架相关
-
Spring Validation框架相关
- 检查请求参数格式的有效性
-
Vue CLI相关
- 前端技术
-
Spring Security框架相关
- 处理认证与授权
-
Redis的基本使用
-
Spring AOP
-
-
项目清单:
- csmall-product:服务器端项目,商品管理
- csmall-passport:服务器端项目,管理员管理
- csmall-web-client:客户端项目
2. 创建csmall-product项目
创建Spring Boot项目,参数:
在后续界面中,关于Spring Boot的版本,应该选择2.x某个版本,且不需要勾选任何依赖项,直接将项目创建出来!
关于pom.xml文件,主要调整Spring Boot父级项目版本,目前使用2.5.x系列版本:
<?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.0</modelVersion>
<!-- 父级项目的配置,主要实现了基础的自动配置与某些依赖项的版本管理 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.9</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 当前项目的配置 -->
<groupId>cn.tedu</groupId>
<artifactId>csmall-product</artifactId>
<version>0.0.1</version>
<!-- 属性配置 -->
<properties>
<java.version>1.8</java.version>
</properties>
<!-- 当前项目使用的依赖项 -->
<!-- scope标签:配置依赖项的作用域 -->
<!-- scope取值为test:此依赖项仅能作用于src/test下的代码,且不参与项目的正式运行时的编译或打包 -->
<dependencies>
<!-- Spring Boot框架的基础依赖项 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring Boot测试框架的依赖项 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 如果以下插件的依赖项报错,你可以: -->
<!-- 1. 显式的添加版本号 -->
<!-- 2. 直接删除整个build标签 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.9</version>
</plugin>
</plugins>
</build>
</project>
3. 创建数据库与数据表
创建mall_pms数据库:
然后,在项目中配置此数据库的Database面板。
可参考视频教程:doc.canglaoshi.org/doc/idea_da…
在Console面板中,粘贴mall_pms.sql中的脚本,并执行,以创建数据表、插入一些模拟数据:
4. 添加数据库编程的依赖
需要添加mybatis-spring-boot-starter依赖,用于实现基于Mybatis的数据库编程。
另外,还需要添加mysql-connector-java依赖,用于连接到MySQL数据库服务器。
在pom.xml中添加依赖项:
<!-- Mybatis整合Spring Boot的依赖项 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!-- MySQL的依赖项 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
当添加以上Mybatis的依赖项后,此项目默认将无法启动(也无法执行任何测试)!因为Spring Boot项目中的与数据库编程相关的依赖项中包含自动配置,当启动项目或执行基于Spring Boot的测试时,会自动读取连接数据库的配置信息,如果尚未配置这些信息,就会报错!
则需要在application.properties中添加配置:
spring.datasource.url=jdbc:mysql://localhost:3306/mall_pms?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
当添加以上配置后,无论是启动项目,还是执行基于Spring Boot的测试,都不再报错,即使以上各属性的配置值有误,也不会报告错误,因为此时只会读取以上信息,并不会真实的连接到数据库!
为了检测以上各配置值是否正确,可以在src/test/java下默认已存在的测试类中编写测试代码:
@SpringBootTest
class CsmallProductApplicationTests {
@Test
void contextLoads() {
}
@Autowired
DataSource dataSource;
@Test
void getConnection() throws Throwable {
dataSource.getConnection();
}
}
如果配置的主机名有误,执行测试会报告错误:
Caused by: java.net.UnknownHostException: localhast
如果配置的端口号有误,执行测试会报告错误:
Caused by: java.net.ConnectException: Connection refused: connect
如果配置的数据库名称有误,执行测试会报告错误:
java.sql.SQLSyntaxErrorException: Unknown database 'mall_pms_haha'
如果配置的用户名有误,执行测试会报告错误:
java.sql.SQLException: Access denied for user 'root1234'@'localhost' (using password: YES)
如果配置的密码有误,执行测试会报告错误:
java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)
如果未配置密码,或配置密码的属性值有误(相当于没有配置预期的属性),执行测试会报告错误:
java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: NO)
5. MySQL中的数据类型与Java属性的类型的对应关系
| MySQL中的类型 | Java属性的类型 |
|---|---|
tinyint / smallint / int | Integer |
bigint | Long |
char / varchar / text系列 | String |
datetime | LocalDateTime |
decimal | BigDecimal |
6. 关于Lombok框架
Lombok是一款可以基于注解在编译期生成特定代码的框架!
在项目中添加依赖项:
<!-- Lombok的依赖项,主要用于简化POJO类的编写 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
当添加以上依赖项后,在POJO类型上,可以添加@Data注解,则Lombok框架会在编译期自动生成此类型中基于所有属性的Setters & Getters、hashCode()、equals()、toString()这些方法(需要当前类的父类存在无参数构造方法)。
在Lombok框架中,还有其它常用注解:
@Setter:添加在属性上,用于生成此属性的Setter方法,也可以添加在类上,用于生成此类中所有属性的Setters方法@Getter:用法与@Setter相同,此注解用于生成Getter方法@ToString:添加在类上,用于生成基于此类中所有属性的toString()方法,此注解可以配置callSuper属性,用于表示是否调用父类的toString()方法@EqualsAndHashCode:添加在类上,用于生成基于此类中所有属性的equals()方法和hashCode()方法@NoArgsConstructor:添加在类上,用于生成此类的无参数构造方法@AllArgsConstructor:添加在类上,用于生成基于此类中所有属性的全参数构造方法@Slf4j:待定
**注意:**在你的开发工具中,需要安装Lombok插件,例如:
如果未使用以上插件,IntelliJ IDEA等开发工具将无法识别生成的代码,经编写时无法给出对应的提示,强行写出的代码也会报错,但是,并不影响运行!
关于以上插件的安装教程:doc.canglaoshi.org/doc/idea_lo…
由于使用Lombok后,应该在开发工具中安装插件,所以,在某些开发团队中是禁止使用Lombok框架的。
7. 关于POJO类的编写规范
POJO类型的编写规范有:
- 各属性均是
private权限 - 各属性均存在规范命名且
public权限的Setters & Getters - 存在基于全部属性的
hashCode()与equals()方法,且,如果2个对象的类型相同、各属性值也全部相同,则必须返回相同的hashCode(),且equals()对比结果为true - 实现
Serializable接口
因为使用的许多框架都会默认你的代码是遵守这些规范的,所以,有些框架在实现有些效果时,会自动的调用Setters & Getters方法,或其它方法,或转换类型为Serializable。
另外,为了便于查看对象的各属性值,还建议添加toString()方法。
8. Mybatis的基础配置
需要使得Mybatis框架清楚各Mapper接口的位置,可以:
- 在各Mapper接口上添加
@Mapper注解 - 【推荐】在配置类上通过
@MapperScan注解指定Mapper接口的根包
采用以上第2种做法时,应该在项目的根包下创建config.MybatisConfiguration类,在类上添加@Configuration注解,将此类标记为配置类,然后通过@MapperScan注解配置Mapper接口的根包:
package cn.tedu.csmall.product.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("cn.tedu.csmall.product.mapper")
public class MybatisConfiguration {
}
在src/main/resources下创建mapper文件夹,用于存放配置SQL语句的XML文件。
在application.properties中添加配置,指定XML文件的位置:
mybatis.mapper-locations=classpath:mapper/*.xml
9. 关于Mapper接口中的抽象方法
-
返回值类型:如果要执行的SQL语句是增、删、改类型的,统一使用
int作为返回值类型,Mybatis会自动返回“受影响的行数”,不推荐使用void;如果要执行的SQL语句是查询类型的,只需要保证返回值类型足以“放得下”你需要的结果值即可 -
方法名称:自定义,不建议重载
根据《阿里巴巴Java开发手册》的规范:
【参考】各层命名规约:
A) Service/DAO 层方法命名规约
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save/insert 做前缀。
5) 删除的方法用 remove/delete 做前缀。
6) 修改的方法用 update 做前缀。
-
参数列表:根据需要执行的SQL语句来设计参数,尽量将多个具有相关性的参数封装起来
10. 关于Mapper映射文件(.xml文件)的配置
-
根标签必须是
<mapper>标签 -
根标签必须配置
namespace属性,取值为映射的接口的全限定名(包名加类名/接口名) -
在根标签的子级,根据需要配置的SQL语句的类型,选择使用
<insert>/<delete>/<update>/<select>标签来配置SQL语句,这些标签必须配置id属性,取值为映射的抽象方法的名称- 在不考虑获取自动编号的ID的情况下,增、删、改使用的标签可以随意调换,但是非常不推荐
-
在
<select>标签上,必须配置resultType或resultMap中的1个属性-
当配置
resultType时,此属性的值是抽象方法对应的类型- 如果是基本数据类型,则直接写类型,例如
resultType="int" - 如果是引用数据类型,则写全限定名,例如
resultType="cn.tedu.csmall.product.pojo.entity.Album" - 如果引用类型是
java.lang包中的,可以不写包名,例如resultType="String"
- 如果是基本数据类型,则直接写类型,例如
-
11. 关于SQL规范
- 在
insert语句中,应该显式的写出字段列表 - 在
select语句中,如果是统计查询,应该使用count(*) - 在
select语句中,如果是查询数据,不允许使用星号表示字段列表 - 在
select语句中,如果是查询列表,必须显式的指定ORDER BY子句
12. 插入相册数据
在项目的根包下创建pojo.entity.Album类:
@Data
public class Album implements Serializable {
private Long id;
private String name;
private String description;
private Integer sort;
private LocalDateTime gmtCreate;
private LocalDateTime gmtModified;
}
在项目的根包下创建mapper.AlbumMapper接口,并声明“插入相册数据”的抽象方法:
public interface AlbumMapper {
int insert(Album album);
}
在src/main/resources/mapper下粘贴得到AlbumMapper.xml文件,通过此文件配置以上接口中的抽象方法映射的SQL语句:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.tedu.csmall.product.mapper.AlbumMapper">
<!-- int insert(Album album); -->
<insert id="insert">
INSERT INTO pms_album (
name, description, sort
) VALUES (
#{name}, #{description}, #{sort}
)
</insert>
</mapper>
在src/test/java的根包下创建mapper.AlbumMapperTests测试类,在类上添加@SpringBootTest注解,在类中自动装配AlbumMapper接口类型的属性,然后,编写并执行测试方法:
@SpringBootTest
public class AlbumMapperTests {
@Autowired
AlbumMapper mapper;
@Test
void insert() {
Album album = new Album();
album.setName("测试数据001");
album.setDescription("测试数据的简介001");
album.setSort(255); // 注意:此值必须是 [0, 255] 区间内的值
mapper.insert(album);
System.out.println("插入数据完成!");
}
}
**注意:**你的测试类,与被测试的类/接口,不要使用完全相同的名称!
如果通过@MapperScan指定的Mapper接口的根包,与实际Mapper接口所在的根包不相符,启动项目或执行基于Spring Boot测试时就会报错:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'cn.tedu.csmall.product.mapper.AlbumMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
如果存在以下错误,执行测试时会出现错误提示:
- 在XML文件中的
<mapper>标签的namespace属性值配置有误 - 在XML文件中的
<insert>等标签的id属性值配置有误 - 在
application.properties中配置的XML文件的位置,与实际使用的XML文件的位置不相符
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.tedu.csmall.product.mapper.AlbumMapper.insert
另外,在插入数据时,如果插入数据的表中的ID是自动编号的,应该在<insert>标签上配置useGeneratedKeys="true"和keyProperty="属性名"这2个属性,以获取自动编号的ID值!例如:
<!-- int insert(Album album); -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO pms_album (
name, description, sort
) VALUES (
#{name}, #{description}, #{sort}
)
</insert>
再次执行测试,可以发现:Mybatis会将自动编号的ID值“回填”到参数对象中keyProperty对应的属性中,例如:
插入数据之前,参数:Album(id=null, name=测试数据007, description=测试数据的简介007, sort=255, gmtCreate=null, gmtModified=null)
插入数据完成!受影响的行数:1
插入数据之后,参数:Album(id=21, name=测试数据007, description=测试数据的简介007, sort=255, gmtCreate=null, gmtModified=null)