在优锐课的java分享中,讨论了关于Spring REST TypeScript生成器,该生成器创建反映后端模型和REST服务的模型和服务。码了很多干货,分享给大家参考学习。
我注意到网络开发人员创建了TypeScript模型和服务来反映我们的后端模型和REST服务。这是一项乏味的工作。更重要的是,在他们最终反映出我们后端的功能之后,这还不是终点。因为我们总是要牢记在软件开发中很常见的一件事...更改。由于一些新的业务需求,修改了后端服务。该更改迫使前端开发人员重新分析后端服务并重构前端应用程序,以便它们与服务器端匹配。
一段时间后,我开始了Web开发的冒险之旅,并提出了可以基于Java中的类型信息生成所有这些代码的想法。我开始寻找一种TypeScript生成器,该生成器将能够基于REST接口在TypeScript中创建模型和服务。正如我的研究表明的那样,已经有一些库提供了这种功能,但是它们都不能满足我们的所有需求,例如:
- 支持JavaBean约定。
- 支持FasterXML / Jackson批注。
- 对Spring框架的支持-生成TypeScript服务,可以调用在Spring中开发的REST API。
- 生成的服务符合Angular和ReactJS的特定要求(Observable或Promises API)。
因此,我们决定启动一个小型的下班时间项目,该项目将提供上述功能。它可以正常工作,我们提出了可以立即使用的解决方案。它已在我们的大多数基于Angular或React的Web应用程序的商业项目中进行了测试和使用。
正如我们的经验所表明的,我们的图书馆带来了巨大的好处。平均生成的代码占Web应用程序代码库的20%,但是就节省的更改和测试工作而言,它是无价的。由于取得了如此可喜的成果,我们公司决定将项目开源。如果你的开发设置在后端使用Spring框架,在前端使用Angular或React,那么你将获得与我们相同的收益。在这篇简短的文章中,我想介绍如何使用我们的spring-rest-2-ts TypeScript生成器进行REST。
例子
为了了解spring-rest2ts生成器的功能,让我们用Java创建一个简单的模型和REST控制器,我们将展示在TypeScript中生成的内容
1 public class BaseDTO { 2 3 private int id; 4 5 @JsonFormat(shape = JsonFormat.Shape.NUMBER) 6 7 private Date updateTimeStamp; 8 9 } 10 11 public class OrderDTO extends BaseDTO { 12 13 private double price; 14 15 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss") 16 17 private LocalDateTime orderTimestamp; 18 19 } 20 21
Spring REST控制器:
1 @Controller 2 3 @RequestMapping("api/order") 4 5 public class OrderCtrl { 6 7 @PostMapping(consumes = {"application/json"}, produces = {"application/json"}) 8 9 @ResponseBody 10 11 @ResponseStatus(HttpStatus.CREATED) 12 13 public OrderDTO createOrder(@RequestBody OrderDTO entity) { 14 15 return entity; 16 17 } 18 19 @RequestMapping(path = "/{id}", method = RequestMethod.GET, produces = {"application/json"}) 20 21 @ResponseBody 22 23 public OrderDTO getOrder(@PathVariable int id) { 24 25 return new OrderDTO(); 26 27 } 28 29 } 30 31
在TypeScript中,对于DTO类,我们获得了两个具有映射继承的接口,其中每个字段都映射到各自的TypeScript类型:
1 export interface Base { 2 3 id: number; 4 5 updateTimeStamp: number; 6 7 } 8 9 export interface Order extends Base { 10 11 price: number; 12 13 /** 14 15 * pattern : dd-MM-yyyy hh:mm:ss 16 17 */ 18 19 orderTimestamp: string; 20 21 }
如我们所见,如果字段具有Jackson批注,则会将其考虑在内。 如果不是,则其转换基于Java类型到TypeScript的映射。 支持类型名称映射。 在Java中,我们通过提供适当的名称映射器来查看OrderDTO,该映射器会切断后缀DTO,然后我们获得Order类型
可观察的基础服务
模型类的映射非常容易理解。 更有趣的是Spring REST控制器的映射,在TypeScript中,该映射已生成用于调用端点的实现。 这种方法隐藏在方法名称,路径和参数下,因此代码可以抵抗后端的更改。 更重要的是,我们将返回类型转换为选定的Web框架。 对于Angular 2+,有一个生成的有效Angular服务可用于注入:
1 @Injectable() 2 3 export class OrderService { 4 5 httpService: HttpClient; 6 7 public constructor(httpService: HttpClient) { 8 9 this.httpService = httpService; 10 11 }
为OrderCtrl生成了OrderService。 在这里,类型名称也由类型名称映射器转换。 如果REST API与Web应用程序不在同一主机上,则可以配置baseURL,它可以是整个主机引用的路径前缀
基于承诺的服务
对于使用Promise API生成器的Web框架,正确的配置还能够生成服务类:
1 export class OrderService { 2 3 baseURL: URL; 4 5 public constructor(baseURL: URL = new URL(window.document.URL)) { 6 7 this.baseURL = baseURL; 8 9 } 10 11 public createOrder(entity: Order): Promise{ 12 13 const url = new URL('/api/order', this.baseURL); 14 15 return fetch(url.toString(), { 16 17 method: 'POST', 18 19 headers: {'Content-Type': 'application/json'}, 20 21 body: JSON.stringify(entity) 22 23 }).then(res => res.json()); 24 25 } 26 27 public getOrder(id: number): Promise { 28 29 const url = new URL('/api/order/' + id + '', this.baseURL); 30 31 return fetch(url.toString(), {method: 'GET'}).then(res => res.json()); 32 33 } 34 35 } 36 37
组态
由于具有更大的灵活性,因此TypeScript生成器通过代码进行配置。 无需配置文件。 这样就可以在需要的地方轻松扩展发电机。 这是最简单的生成器配置器:
1 Rest2tsGenerator tsGenerator = new Rest2tsGenerator(); 2 3 // Java Classes filtering 4 5 tsGenerator.setModelClassesCondition(new ExtendsJavaTypeFilter(BaseDTO.class)); 6 7 tsGenerator.setRestClassesCondition(new ExtendsJavaTypeFilter(BaseCtrl.class)); 8 9 // Java model classes converter setup 10 11 JacksonObjectMapper jacksonObjectMapper = new JacksonObjectMapper(); 12 13 jacksonObjectMapper.setFieldsVisibility(JsonAutoDetect.Visibility.ANY); 14 15 modelClassesConverter = new ModelClassesToTsInterfacesConverter(jacksonObjectMapper); 16 17 modelClassesConverter.setClassNameMapper(new SubstringClassNameMapper("DTO", "")); 18 19 tsGenerator.setModelClassesConverter(modelClassesConverter); 20 21 // Spring REST controllers converter 22 23 restClassesConverter = new SpringRestToTsConverter(new Angular4ImplementationGenerator()); 24 25 restClassesConverter.setClassNameMapper(new SubstringClassNameMapper("Ctrl", "Service")); 26 27 tsGenerator.setRestClassesConverter(restClassesConverter); 28 29 // set of java root packages for class scanning 30 31 javaPackageSet = Collections.singleton("com.blueveery.springrest2ts.examples"); 32 33 tsGenerator.generate(javaPackageSet, Paths.get("../target/ts-code")); 34 35
文章写道这里,感谢大家的观看。如有不足支持,欢迎补充评论。
更欢迎朋友们点赞关注,和我一起细说探讨架构那些事。