Jmix 中 REST API 的两种实现
你知道吗,在 Jmix 中,REST API 有两种实现方式!
很多应用是采取前后端分离的方式进行开发。这种模式下,对前端的选择相对灵活,可以根据团队的擅长技能选择流行的 Angular/React/Vue 之一,或者前端为App/小程序等手机应用。Jmix 的一种典型应用场景就是作为这种类型应用程序的高级别管理 UI 和后端。为此,Jmix 提供了强大的通用 REST API 功能,支持包括开箱即用的实体、文件、元数据、用户会话的 API 以及经过简单配置就能支持的业务逻辑(服务)REST API。
由于 Jmix 是基于 Spring Boot 框架,因此也支持 Spring 的 RestController
。那么对于 Spring 的 REST API 机制和 Jmix 提供机制,究竟有什么不同,而我们在开发时又该如何选择呢?本文将通过具体的代码示例,介绍这两种 API 的区别,相信看完之后,该如何选择您心里应该有数了。
数据模型和服务
我们假设一个简单的场景,为了给用户提供凑单功能,我们在后端写一个服务用于查询低于某个价格的产品(Product
),并将满足条件的产品列表返回给客户端。
数据模型
首先我们构建一个简单的 JPA 实体:Product
类,包含名称和价格两个属性:
@JmixEntity
@Table(name = "SLS_PRODUCT")
@Entity(name = "sls_Product")
public class Product {
@JmixGeneratedValue
@Column(name = "ID", nullable = false)
@Id
private UUID id;
@InstanceName
@Column(name = "NAME")
private String name;
@Column(name = "PRICE")
private Double price;
... // 其他属性
}
实体通过 Jmix Studio 创建可以选择其他实体特性,比如版本、实体审计、软删除属性等。
服务
可以像普通 Spring Boot 应用那样,自己手动创建一个 @Service
类。也可以通过 Jmix Studio 提供的创建 bean 的功能创建 Service。这里我们用 Jmix Studio 创建一个 Bean,该功能默认创建带 @Component
注解的类,我们手动将类注解修改为 @Service
:
@Service("sls_ProductService")
public class ProductService {
@Autowired
private DataManager dataManager; // 插入代码段时,默认注入带有权限检查的 DataManager
public List<Product> getProductsCheaperThan(Double price){
// 注意,这里我们并没有对输入参数 price 做检查
List<Product> productList = dataManager.load(Product.class)
.query("select p from sls_Product p " +
"where p.price < :priceInput")
.parameter("priceInput", price)
.list();
return productList;
}
}
这里的加载实体列表代码,我们通过 Studio 的代码段功能自动添加。
服务中,我们使用了 Jmix 的 DataManager
和 JPQL 查询语句加载实体,并使用方法的输入参数作为 JPQL 的参数。Jmix 的持久层也支持 Spring Data Repository 或者 MyBatis。而使用 DataManager
的一个好处是可以利用 Jmix 的安全机制,控制 API 调用方对实体的访问权限。
Jmix 服务 API
Jmix 服务(Service) API 可以将任意 Spring bean 作为 HTTP 接口开放。Jmix 负责 HTTP 交互,例如,提供 HTTP 响应编码、进行错误处理等。下图是 Jmix 服务 API 的流程图:
可以看到,作为应用程序开发者,仅需要编写服务代码。另外,还需做一些配置:
- 在项目的 resources 目录添加 rest-services.xml,用于配置可作为 REST API 使用的服务及其方法,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<services xmlns="http://jmix.io/schema/rest/services">
<service name="sls_ProductService"> <!-- 指定服务名称 -->
<method name="getProductsCheaperThan"> <!-- 指定方法名称 -->
<param name="price" type="java.lang.Double"/> <!-- 指定方法参数和类型 -->
</method>
<!-- 可以添加服务中其他方法 -->
</service>
<!-- 可以添加其他服务 -->
</services>
- 在项目的
application.properties
文件中,设置jmix.rest.services-config
参数,指定上面配置的 xml 文件:
jmix.rest.services-config = com/abmcode/sales/rest-services.xml
完成这些配置之后,就可以通过 REST 客户端调用了,URL 为 /rest/services/<service_name>/<method_name>
。例如,通过 Postman 调用:
服务 API 会默认使用 Jmix 的安全机制:API 端口需要使用认证 token 进行访问,而且用户需要有访问 REST API 和所查询实体的权限。另外,Jmix 的服务 API 也支持匿名访问。
Spring 控制器 API
然后我们再看看 Spring 的 RestController
方式。首先,我们定义一个控制器:
@RestController("sls_ProductController")
@RequestMapping("/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("priceunder")
public List<Product> getPriceUnder(@RequestParam Double price) throws Throwable {
if (price < 0) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "价格参数必须大于 0"); // 自定义控制器层的参数检查,抛出请求异常。
}
return productService.getProductsCheaperThan(price);
}
}
Jmix 中的控制器接口默认都是匿名的,但是为匿名用户配置能访问实体信息又不够安全,Jmix 提供了一个应用程序属性,支持使用 Jmix 安全机制对自定义控制器进行保护:
# 支持逗号分隔的多个 pattern
jmix.rest.authenticatedUrlPatterns=/products/**
然后,重启服务就可以通过 Postman 进行调用。注意,这里的 URL 与服务 URL 不同,直接使用了控制器中定义的路径:
结论
通过上面的代码,我们可以看到,在 Jmix 中使用两种类型的 REST API 其实都不复杂,但是,也是各有优势:
Jmix 服务 API:
- 不用编写控制器代码,仅通过 XML 配置即可使用
- 默认使用 Jmix 的安全机制
- 可以使用 Fetch plan 定义返回实体的字段
Spring 控制器:
- 更加灵活,可以使用 Spring 控制器自定义 HTTP 状态码、响应类型或者异常错误
- 除了使用服务层的实体控制外,还可以在控制器层使用自定义的 DTO 对返回实体的信息做进一步控制
因此,在大多数情况下,我们仅使用 Jmix 的服务 API 就能够满足使用要求。针对部分复杂场景可以使用 Spring 控制器 API。
文中使用的 Jmix 版本:1.3.1
Jmix 中 REST API 的两种实现的更多相关文章
- linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...
- 实验--使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用(杨光)
使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 攥写人:杨光 学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程 ...
- LInux内核分析--使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
实验者:江军 ID:fuchen1994 实验描述: 选择一个系统调用(13号系统调用time除外),系统调用列表参见http://codelab.shiyanlou.com/xref/linux-3 ...
- 实验四——使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
实验目的: 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 实验过程: 查看系统调用列表 get pid 函数 #include <stdio.h> #include & ...
- Linux内核设计第四周学习总结 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
陈巧然原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验目的: 使用库函数A ...
- Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式 目录 Pycharm使用技巧(转载) Python第一天 安装 shell 文件 Py ...
- Java中HashMap遍历的两种方式
Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...
- jqGrid中实现radiobutton的两种做法
http://blog.sina.com.cn/s/blog_4f925fc30102e27j.html jqGrid中实现radiobutton的两种做法 ------------------- ...
- php获取数组中重复数据的两种方法
分享下php获取数组中重复数据的两种方法. 1,利用php提供的函数,array_unique和array_diff_assoc来实现 <?php function FetchRepeatMem ...
随机推荐
- 零基础学Java(11)自定义类
前言 之前的例子中,我们已经编写了一些简单的类.但是,那些类都只包含一个简单的main方法.现在来学习如何编写复杂应用程序所需要的那种主力类.通常这些类没有main方法,却有自己的实例字段和实例方 ...
- git和提交分支
实习到今天,已经开始做项目一段时间了,当然只是实习生的个人项目. 项目是导师发在git上面的,要求我们用git的PR提交 可是我不会啊...git仅仅是简单的个人提交总的项目到仓库里,什么新建分支,p ...
- s905l3a系列刷armbian 教你从0搭建自己的博客
最近服务器又更换了,原来的有一点点小意外(一个电阻给我焊接时搞掉了). 哎~~今天,我淘到了一个好东西----CM311-3a,配置很诱人,价格也不贵,60绰绰有余 比较 CM311-3a N1(炒到 ...
- 面试突击73:IoC 和 DI 有什么区别?
IoC 和 DI 都是 Spring 框架中的重要概念,就像玫瑰花与爱情一样,IoC 和 DI 通常情况下也是成对出现的.那 IoC 和 DI 什么关系和区别呢?接下来,我们一起来看. 1.IoC 介 ...
- 使用.NET简单实现一个Redis的高性能克隆版(六)
译者注 该原文是Ayende Rahien大佬业余自己在使用C# 和 .NET构建一个简单.高性能兼容Redis协议的数据库的经历. 首先这个"Redis"是非常简单的实现,但是他 ...
- 节后复工,Apache DolphinScheduler喜迎7位新Committer
Apache DolphinScheduler(Incubating)社区在节后上周第一周就迎来了好消息,经过 Apache DolphinScheduler PPMC 们的推荐和投票,我们高兴的宣布 ...
- 【喜讯】新一代大数据任务调度 - Apache DolphinScheduler 社区荣获OSCHINA年度 “最佳技术团队”...
新一代大数据任务调度 - Apache DolphinScheduler 继 11 月 19 日由 InfoQ 举办.在 300+ 参评项目中脱颖而出获得 "2020 年度十大开源新锐项目 ...
- Java SE 9 多版本兼容 JAR 包示例
Java SE 9 多版本兼容 JAR 包示例 作者:Grey 原文地址:Java SE 9 多版本兼容 JAR 包示例 说明 Java 9 版本中增强了Jar 包多版本字节码文件格式支持,也就是说在 ...
- 状态 :睡眠中,进程ID:13431,yum提示Another app is currently holding the yum lock; waiting for it to exit...
问题描述: 今天想在虚拟机上重新安装docker然后使用到yum命令报错: 解决办法: [root@localhost ~]# rm -f /var/run/yum.pid 然后重新运行刚才的yum命 ...
- day29--Java泛型02
Java泛型02 5.自定义泛型 5.1自定义泛型类 基本语法: class 类名<T,R...>{//-表示可以有多个泛型 成员 } 注意细节: 普通成员可以使用泛型(属性.方法) 使用 ...