0.总配置
pom.xml
<?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>
<packaging>pom</packaging>
<modules>
<module>myinterceptor</module>
<module>tk-mybatis</module>
<module>jwt</module>
<module>spi</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cskaoyan</groupId>
<artifactId>basic-skill</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>basic-skill</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.拦截器配置-HandlerInterceptor
1.1 概念
- 一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的
- 而在Spring中,基于Filter这种方式可以实现Bean预处理、后处理。比如注入FilterRegistrationBean,然后在这个Bean上传递自己继承Filter实现的自定义Filter进入即可。
- 而Spring MVC也有拦截器,不仅可实现Filter的所有功能,还可以更精确的控制拦截精度。Spring MVC提供的org.springframework.web.servlet.handler.HandlerInterceptor这个适配器,实现此接口就可以实现自己的拦截器。
1.2 Filter和Interceptor的区别:
- Filter依赖Servlet容器,而Interceptor不依赖于Servlet容器
- Filter是基于函数回调(doFilter()方法)的,而Interceptor则是基于Java反射的(AOP思想)。
- Filter对几乎所有的请求起作用,而Interceptor只能对action请求起作用。
- Interceptor可以访问Action的上下文,值栈里的对象,而Filter不能。
- 在action的生命周期里,Interceptor可以被多次调用,而Filter针对一个请求只会被调用一次。
- Filter在过滤是只能对request和response进行操作,而interceptor可以对request、response、handler、modelAndView、exception进行操作。
1.3 代码实现:
1.3.1 结构
pom.xml(myinterceptor的pom配置)
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>basic-skill</artifactId>
<groupId>com.cskaoyan</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.cskaoyan</groupId>
<artifactId>myinterceptor</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
1.3.2 MyInterceptor(自定义拦截器)
/**
* @Author:gaoyuan
* @Description:
* @DateTime:2021/4/19 21:20
**/
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("预处理拦截成功!");
return false;
}
}
1.3.3 MyMvcConfig(定义配置类,使拦截器生效)
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry){
InterceptorRegistration interceptorRegistration = registry.addInterceptor(new MyInterceptor());
// ** 表示拦截所有的请求
interceptorRegistration.addPathPatterns("/**");
}
}
1.3.4 TestController(控制请求跳转)
/**
* @Author:gaoyuan
* @Description:
* @DateTime:2021/4/19 21:22
**/
@RestController
public class TestController {
@RequestMapping("/hello")
public String helloInterceptor() {
return "11111";
}
}
1.3.5 InterceptorApplicaltion(主类)
/**
* @Author:gaoyuan
* @Description:
* @DateTime:2021/4/19 21:30
**/
@SpringBootApplication
public class InterceptorApplicaltion {
public static void main(String[] args) {
SpringApplication.run(InterceptorApplicaltion.class,args);
}
}
执行流程:
结果:
拦截放行:
2.tk-Mybatis
2.1 概念
TK-Mybatis是一个在Mybatis基础之上只做增强,不做改变的工具。为简化开发,提高效率而生。
通用 Mapper4 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及Example 相关的单表操作。通用 Mapper 是为了解决 MyBatis 使用中 90% 的基本操作,使用它可以很方便的进行开发,可以节省开发人员大量的时间。
官网:https://github.com/abel533/Mapper/wiki
2.2结构及导包
pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>basic_skillTest</artifactId>
<groupId>com.gy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.gy</groupId>
<artifactId>tk-mybatis</artifactId>
<dependencies>
<!--Mysql连接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!--durid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.16</version>
</dependency>
<!--tk-Mybatis-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
<!--MapStruct-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.0.Final</version>
</dependency>
</dependencies>
</project>
2.3 配置
数据源配置
application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/csmall?serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
#debug: true,忽略不必要的报错信息
# debug: true
代码配置
配置实体类和表的映射
数据库:
UserDO
/**
* @Author:gaoyuan
* @Description:
* @DateTime:2021/4/19 22:17
**/
@Table(name = "user")//name配置为表名
@Data
public class UserDO {
@Id//主键必须加id注解
Integer id;
// @Column表示该字段是普通字段
@Column(name = "name")
String username;
Integer age;
}
UserDTO
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class UserDTO {
Integer id;
String name;
Integer userAge;
}
配置Mapper
UserMapper
public interface UserMapper extends Mapper<UserDO> {
}
MyUserConverter
@Mapper(componentModel = "spring")
public interface MyUserConverter {
@Mappings({
@Mapping(source = "id",target ="id" ),
@Mapping(source = "username",target ="name" ),
@Mapping(source = "age",target ="userAge" )
})
UserDTO userDO2UserDTO(UserDO userDO);
List<UserDTO> userDOs2UserDTOs(List<UserDO> userDOs);
}
配置扫描包
TkMybatisAppolication(启动类)
@SpringBootApplication
@MapperScan(basePackages = "com.mapper")//这个注解加到启动类上或者是配置类上
public class TkMybatisAppolication {
public static void main(String[] args) {
SpringApplication.run(TkMybatisAppolication.class, args);
}
}
2.4 测试
testTK
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class testTK {
@Autowired
UserMapper userMapper;
// @Autowired
// MyUserConverter converter;
@Test
public void interUser() {
UserDO userDO = new UserDO();
userDO.setId(5);
userDO.setUsername("dddd");
userDO.setAge(777);
int insert = userMapper.insert(userDO);
System.out.println(insert);
}
}
查询,返回表中所有的记录
@Test
public void selectUsers() {
//返回表中所有的记录
@Test
public void selectUsers() {
//返回表中所有的记录
List<UserDO> users = userMapper.selectAll();
for (UserDO user : users) {
System.out.println(user);
}
根据主键查询
@Test
public void selectUsers() {
// 根据主键查询
UserDO user = userMapper.selectByPrimaryKey(1);
System.out.println(user);
UserDO u = new UserDO();
u.setId(2);
UserDO user2 = userMapper.selectByPrimaryKey(u);
System.out.println(user2);
UserDTO userDTO = new UserDTO();
userDTO.setId(user2.getId());
userDTO.setUserAge(user2.getAge());
userDTO.setName(user2.getUsername());
System.out.println(userDTO);
除主键之外的,条件查询
@Test
public void selectUsers() {
// 除主键之外的,条件查询
Example example = new Example(UserDO.class);
Example.Criteria criteria = example.createCriteria();
// 每一个条件中的property参数,指的是是实体类的属性名而非数据库表中的列名
criteria
.andGreaterThan("age", 444)
.orEqualTo("username", "bbbbb");
List<UserDO> users = userMapper.selectByExample(example);
for (UserDO user : users) {
System.out.println(user);
}
}
更新
使用参数对象的每一个属性值,去更新数据库中,满足条件的记录(条件有的就更新,没有的就为null)
@Test
public void update() {
// 更新操作
UserDO user = new UserDO();
user.setId(1);
user.setUsername("dadADADADADA");
// 该方法使用参数对象的每一个属性值,去更新数据库中,满足条件的记录
int effectiveRows = userMapper.updateByPrimaryKey(user);
System.out.println(effectiveRows);
}
使用参数对象的每一个不为null的属性值,去更新数据库中,满足条件的记录
@Test
public void update() {
// 更新操作
UserDO user = new UserDO();
user.setId(1);
user.setUsername("ffffffffff");
// 该方法使用参数对象的每一个不为null的属性值,去更新数据库中,满足条件的记录
int e = userMapper.updateByPrimaryKeySelective(user);
System.out.println(e);
}
带条件的更新
@Test
public void update() {
// 更新操作
UserDO user = new UserDO();
user.setId(5);
user.setUsername("wwwwwwwww");
// 带条件的更新
Example example = new Example(UserDO.class);
example.createCriteria()
.andGreaterThan("age", 444);
// int i = userMapper.updateByExample(user, example);
// System.out.println(i);
int i1 = userMapper.updateByExampleSelective(user, example);
System.out.println(i1);
}
3.MapStruct
3.1概念
在一个成熟的工程中,尤其是现在的分布式系统中,应用与应用之间,还有单独的应用细分模块之后,DO一般不会让外部依赖,这时候需要在提供对外接口的模块里放DTO用于对象传输,也即是DO对象对内,DTO对象对外,DTO 可以根据业务需要变更,并不需要映射DO 的全部属性。
DTO : Data Transport Object (数据传输对象)
VO: View Object (视图解析对象)
3.2 导包
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.0.Final</version>
</dependency>
3.3 定义转换器接口
MyUserConverter
@Mapper(componentModel = "spring")
public interface MyUserConverter {
@Mappings({
@Mapping(source = "id",target ="id" ),
@Mapping(source = "username",target ="name" ),
@Mapping(source = "age",target ="userAge" )
})
UserDTO userDO2UserDTO(UserDO userDO);
List<UserDTO> userDOs2UserDTOs(List<UserDO> userDOs);
}
UserDTO
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class UserDTO {
Integer id;
String name;
Integer userAge;
}
3.4 测试类:
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
//@MapperScan("com")
public class testTK {
@Autowired
UserMapper userMapper;
@Test
public void testMapStruct() {
UserDO user = userMapper.selectByPrimaryKey(1);
System.out.println(user);
UserDTO userDTO = new UserDTO();
userDTO.setId(user.getId());
userDTO.setUserAge(user.getAge());
userDTO.setName(user.getUsername());
System.out.println(userDTO);
}
}
使用MapStruct,将 UserDO类型转化为UserDTO类型
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
//@MapperScan("com")
public class testTK {
@Autowired
UserMapper userMapper;
@Autowired
MyUserConverter converter;
@Test
public void testMapStruct() {
// 使用MapStruct,将 UserDO类型转化为UserDTO类型
List<UserDO> userDOs = userMapper.selectAll();
for (UserDO userDO : userDOs) {
System.out.println(userDO);
}
List<UserDTO> userDTOs = converter.userDOs2UserDTOs(userDOs);
for (UserDTO userDTO : userDTOs) {
System.out.println(userDTO);
}
}
}
4.SPI
4.1概念
- SPI 全称为(Service Provider Interface) ,是JDK内置的一种服务提供发现机制。目前有不少框架用它来做服务的扩展发现(Dubbo、JDBC等)
- 简单来说,它就是一种动态替换发现的机制
- 举个例子来说, 有个接口,想运行时动态的给它添加实现,你只需要添加一个实现。
4.2 Java SPI的约定(约定俗成)
- 当服务的提供者提供了服务接口的一种实现之后,在jar包的META-INF/Services/目录中同时创建一个以服务接口命名的文件
- 该文件里就是实现该服务接口的具体实现类
- 而当外部程序装配这个模块的时候,就能通过该jar包META-INF/Services/的配置文件找到具体的实现类名
- 并装载实例化,完成模块的注入
- 基于这样的一个约定就能很好的找到服务接口的实现类,而不需要在代码里指定。
4.3 实践
4.3.1定义接口
PayService
public interface PayService {
void pay(double amout);
}
4.3.2定义接口实现
AliPay
public class AliPay implements PayService {
@Override
public void pay(double amout) {
System.out.println("ali pay");
}
}
WeChatPay
public class WeChatPay implements PayService {
@Override
public void pay(double amout) {
System.out.println("we chat pay");
}
}
4.3.3定义配置文件
com.pay.PayService
com.pay.impl.AliPay
com.pay.impl.WeChatPay
4.3.4测试
SPIApplication
public class SPIApplication {
public static void main(String[] args) {
// 调用实现了PayService接口的那些类的不同的支付功能
// 普通方式
// PayService pay = null;
// //pay = new WeChatPay();
// //pay.pay(100);
//
// pay = new AliPay();
// pay.pay(200);
// SPI方式
ServiceLoader<PayService> load = ServiceLoader.load(PayService.class);
Iterator<PayService> iterator = load.iterator();
while (iterator.hasNext()) {
PayService next = iterator.next();
next.pay(100.0);
}
}
}