介绍
Quarkus在日常开发中是可以替代SpringBoot的。
Quarkus是 Red Hat为GraalVM 和 HotSpot 量身定制用程序。特点是启动超快,内存极低,并且在容器编排平台(如Kubernetes)中提供了近乎即时的向上扩展和高密度的内存利用率。并且基于GraalVM,为我们提供了编译成native程序的能力。如果你觉得SpringBoot的启动速度太慢了内存占用率太高了,那么可以在日常开发中尝试一下Quarkus,也许会给你不一样的体验。我将通过一系列的教程,来介绍如何使用Quarkus。
本文章将演示如何快速的通过idea工具来辅助我们快速的构建一个quarkus项目并用Quarkus快速实现一个CRUD操作
创建quarkus项目
在左边的菜单中选择quarkus,这里要注意 quarkus 只支持jdk11以上的版本,所以这里我选择jdk17, 项目的管理方式为 maven
我们先选择如下依赖,resteasy 相当于springmvc,openapi相当于swagger。这里还差一个mybatisplus的依赖,这里选择有点问题。
因为我们要做演示的是Web项目, 所以这里我们选择Web依赖, 这里需要注意的是resteasy系列的依赖互相不兼容,我没有选择
引入quarkus-resteasy-jsonb依赖时记得把原来quarkus-resteasy-reactive也去掉,这俩其实只是对同一个API的不同实现,会冲突的,同时只能存在一个,如果要都有,就用一个quarkus-resteasy-reactive-jsonb依赖替换掉
项目结构
添加依赖配置
不过我们的项目目前还不能启动因为少了一个resteasy的相关的依赖, 因为我们需要在接口直接传入对象, 我比较习惯在请求体中传入json来达到传输对象的目的, 而且参数的校验比较容易
我们在pom中再添加一下mybatisplus跟lombok的依赖
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.mybatis</groupId>
<artifactId>quarkus-mybatis-plus</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
所有依赖
<properties>
<compiler-plugin.version>3.12.1</compiler-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.9.4</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.2.5</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mysql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkiverse.mybatis</groupId>
<artifactId>quarkus-mybatis-plus</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
添加mysql的配置
quarkus.http.port=8081
quarkus.datasource.db-kind=mysql
quarkus.datasource.password=root
quarkus.datasource.username=root
quarkus.datasource.jdbc.url=jdbc:mysql://localhost/graalvm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
quarkus.datasource.jdbc.max-size=16
启动项目
启动项目准备
创建一张user表
CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL,
`address` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
再创建一个user的实体类
package com.billetsdoux.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private String address;
private Integer age;
private String password;
}
mapper层
package com.billetsdoux.repository;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.billetsdoux.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserRepository extends BaseMapper<User> {
}
service层如下,查询单个,分页查询,更新,删除,新增操作
package com.billetsdoux.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.billetsdoux.entity.User;
import com.billetsdoux.repository.UserRepository;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class UserService {
@Inject
UserRepository userRepository;
public User findById(Long id){
return userRepository.selectById(id);
}
public Page<User> list(String name,String address,Integer age,Integer pageNo,Integer pageSize){
Page<User> page = userRepository.selectPage(new Page<>(pageNo, pageSize), new QueryWrapper<User>()
.eq(StringUtils.isNotBlank(name), "name", name)
.eq(StringUtils.isNotBlank(address), "address", address)
.eq(null!=age, "age", age));
return page;
}
public boolean insert(User user){
return userRepository.insert(user)>0;
}
public boolean update(User user){
return userRepository.updateById(user) > 0;
}
public boolean delete(Long id){
return userRepository.deleteById(id) > 0;
}
}
controller层
package com.billetsdoux.controller;
import com.billetsdoux.entity.User;
import com.billetsdoux.service.UserService;
import com.billetsdoux.util.BaseResponse;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;
@Path("/user")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserController {
@Inject
UserService userService;
@GET
@Path("/search/{id}")
public User searchById(@PathParam("id") Long id){
return userService.findById(id);
}
@GET
@Path("/list")
public BaseResponse<List<User>> list(@QueryParam("name") String name,
@QueryParam("address") String address,
@QueryParam("age") Integer age,
@QueryParam("pageNo") Integer pageNo,
@QueryParam("pageSize") Integer pageSize
){
return BaseResponse.success(userService.list(name, address, age, pageNo, pageSize).getRecords());
}
@POST
@Path("/add")
public BaseResponse addUser(User user){
return userService.insert(user) ? BaseResponse.success() : BaseResponse.error();
}
@DELETE
@Path("/delete/{id}")
public BaseResponse delete(@PathParam("id") Long id){
return userService.delete(id) ? BaseResponse.success() : BaseResponse.error();
}
@PUT
@Path("/update")
public BaseResponse updateUser(User user){
return userService.update(user) ? BaseResponse.success() : BaseResponse.error();
}
}
新增了一个BaseResponse
package com.billetsdoux.util;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class BaseResponse<T> {
private static final int CODE_SUCCESS = 200;
private static final int CODE_FAIL = 500;
private static final int CODE_ERROR = 500;
private static final int CODE_NO_LOGIN = 300;
private int code;
private String msg;
private T data;
public BaseResponse(int code, String msg, T data) {
this.setCode(code);
this.setMsg(msg);
this.setData(data);
}
public static <T> BaseResponse<T> success() {
return new BaseResponse<T>(CODE_SUCCESS, "success", null);
}
public static <T> BaseResponse<T> success(String message) {
return new BaseResponse<T>(CODE_SUCCESS, message, null);
}
public static <T> BaseResponse<T> success(T data) {
return new BaseResponse<T>(CODE_SUCCESS, "success", data);
}
public static <T> BaseResponse<T> success(String message, T data) {
return new BaseResponse<T>(CODE_SUCCESS, message, data);
}
public static <T> BaseResponse<T> error() {
return new BaseResponse<T>(CODE_ERROR, "fail", null);
}
public static <T> BaseResponse<T> error(String message) {
return new BaseResponse<T>(CODE_ERROR, message, null);
}
public static <T> BaseResponse<T> error(T data) {
return new BaseResponse<T>(CODE_ERROR, "fail", data);
}
public static <T> BaseResponse<T> error(String message, T data) {
return new BaseResponse<T>(CODE_ERROR, message, data);
}
public static <T> BaseResponse<T> badrequest() {
return new BaseResponse<T>(CODE_FAIL, "no identifier arguments", null);
}
public static <T> BaseResponse<T> badrequest(String message) {
return new BaseResponse<T>(CODE_FAIL, message, null);
}
public static <T> BaseResponse<T> badrequest(T data) {
return new BaseResponse<T>(CODE_FAIL, "no identifier arguments", data);
}
public static <T> BaseResponse<T> badrequest(String message, T data) {
return new BaseResponse<T>(CODE_FAIL, message, data);
}
public static <T> BaseResponse<T> noLogin(String message) {
return new BaseResponse<T>(CODE_NO_LOGIN, message, null);
}
}
简单的crud的代码就只有这些
启动项目
由于它没有main方法作为入口,所以我们需要在命令行之行如下命令启动项目。
./mvnw compile quarkus:dev
由于quarkus在第一次启动的时候会通过网络去下载一些依赖, 网络不好的同学可以通过maven配置文件settings.xml中配置aliyun镜像下载,
可以全文搜索 maven-default-http-blocker 配置在这个配置之下
<!-- 阿里镜像 -->
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
配置之后可以使用如下命令启动
./mvnw compile quarkus:dev -s D:\ProgramFiles\maven\apache-maven-3.9.6\conf\settings.xml
页面测试
项目启动好了,访问 localhost:8080/q/swagger-ui 进入swagger页面
插入一条数据
查询刚添加的数据
更新一下刚查询的数据
至此,我们用quarkus+mybatisplus完成了基础的crud操作。
注意总结
- 注意 quarkus 只支持jdk11以上的版本,所以这里我选择jdk17
- 注意注解导包是否正确
- 注意的是resteasy系列的依赖互相不兼容
- 注意quarkus在启动的时候会通过网络去下载一些依赖 可以通过aliyun仓库快一点
- maven版本建议在3.8.0以上