unionj-generator快速上手-前端篇

Photo by Proxyclick Visitor Management System

继续上一篇文章《unionj-generator快速上手-后端篇》,本文介绍如何通过unionj-generator生成前端代码并在vue项目中使用。

网页版代码下载器


我们为了减轻后端同事帮前端同事生成客户端代码的负担,开发了一个网页版代码下载器,可以点击openapi-svc项目github仓库地址查看源码。

本地开发

  • 下载unionj-generator源码
git clone [email protected]:unionj-cloud/unionj-generator.git
  • 切到v1.6.0分支
git checkout tags/v1.6.0 -b v1.6.0
  • 安装unionj-generator到本地maven仓库
mvn clean install -Dmaven.test.skip=true
  • 下载openapi-svc源码:
git clone [email protected]:unionj-cloud/openapi-svc.git
  • 编译打包
mvn clean install -Dmaven.test.skip=true
  • 打包docker镜像
cd svc-server && docker build -t openapi-svc .
  • 启动容器
docker run -it --rm  -p 8080:8080 openapi-svc
  • 打开浏览器,看到如下截图所示的界面即表示启动成功
image
  • 推送镜像到远程镜像仓库
docker tag openapi-svc $yourdockerimageregisry/openapi-svc:$version
docker push $yourdockerimageregisry/openapi-svc:$version

k8s部署

  • 下载k8s部署文件

wget命令

wget https://github.com/unionj-cloud/openapi-svc/blob/main/svc-server/deployment.yaml

curl命令

curl https://github.com/unionj-cloud/openapi-svc/blob/main/svc-server/deployment.yaml -o deployment.yaml
  • 修改ingress配置(用于公网访问)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: openapi-ingress
spec:
  rules:
    - host: RLACE_WITH_YOUR_OWN_HOST
      http:
        paths:
          - path: /openapi-server
            pathType: Prefix
            backend:
              service:
                name: openapi-service
                port:
                  number: 8080

RLACE_WITH_YOUR_OWN_HOST: 替换成你的k8s ingress地址

  • 部署
kubectl apply -f deployment.yaml

接口

有两个接口地址可供发起请求,用于制作CI/CD工具或者前端工程化工具

  • POST /ts/upload: 上传OpenAPI 3.0规范的json文档下载代码zip压缩包
    请求参数:file
    返回参数:二进制流

  • GET /ts/url:通过url参数传递OpenAPI 3.0规范的json文档下载地址下载代码zip压缩包
    请求参数:url
    返回参数:二进制流

后端接口改造


为了配合本文,我们对上一篇文章的后端接口代码做了修改,引入了内嵌的mongodb,在内存里存储数据,用户id类型改成了string字符串类型,然后实现了接口,保证前端可以正常请求到。

POM


  org.springframework.boot
  spring-boot-starter-data-mongodb


  de.flapdoodle.embed
  de.flapdoodle.embed.mongo

UserController

package cloud.unionj.guide.api.controller;

import cloud.unionj.guide.proto.UserProto;
import cloud.unionj.guide.vo.*;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

/**
 * @author created by wubin
 * @version v0.0.1
 * description: cloud.unionj.guide.api.controller
 * date:2021/6/9
 */
@RestController
@RequiredArgsConstructor
public class UserController implements UserProto {

  private final MongoTemplate mongoTemplate;

  @SneakyThrows
  @Override
  public ResponseEntity getApiUserAvatar(String id) {
    UserDetailVO vo = mongoTemplate.findById(id, UserDetailVO.class, "guide");
    File file = new File(vo.getAvatar());
    return ResponseEntity.ok()
        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName())
        .header(HttpHeaders.CONTENT_TYPE, "application/octet-stream")
        .body(Files.readAllBytes(Paths.get(vo.getAvatar())));
  }

  @Override
  public ResultVO getApiUserDetail(String id) {
    UserDetailVO vo = mongoTemplate.findById(id, UserDetailVO.class, "guide");
    ResultVO ret = new ResultVO<>();
    ret.setCode(0);
    ret.setData(vo);
    return ret;
  }

  @SneakyThrows
  @Override
  public ResultVO postApiUserEdit(String name, Integer age, String sex, String id, MultipartFile avatar) {
    byte[] bytes = avatar.getBytes();
    String outputDir = System.getProperty("user.dir") + "/output";
    new File(outputDir).mkdirs();
    Path path = Paths.get(outputDir + "/" + avatar.getOriginalFilename());
    Files.write(path, bytes);
    DBObject user = BasicDBObjectBuilder.start()
        .add("name", name)
        .add("age", age)
        .add("sex", sex)
        .add("avatar", path.toString())
        .add("_id", new ObjectId(id))
        .get();
    mongoTemplate.save(user, "guide");
    ResultVO ret = new ResultVO<>();
    ret.setCode(0);
    ret.setData("OK");
    return ret;
  }

  @Override
  public ResultVO> postApiUserPage(UserPageReqVO body) {
    List vos = mongoTemplate.findAll(UserDetailVO.class, "guide");
    PageResultVO pageResultVO = new PageResultVO<>();
    pageResultVO.setPages(1);
    pageResultVO.setCurrent(1);
    pageResultVO.setSize(10);
    pageResultVO.setTotal(1l);
    pageResultVO.setItems(vos);
    ResultVO> ret = new ResultVO<>();
    ret.setCode(0);
    ret.setData(pageResultVO);
    return ret;
  }

  @Override
  public ResultVO postApiUserRegister(String username, String password) {
    DBObject user = BasicDBObjectBuilder.start()
        .add("username", username)
        .add("password", password)
        .get();
    DBObject savedUser = mongoTemplate.save(user, "guide");
    UserRegisterRespVO vo = new UserRegisterRespVO();
    vo.setId(((ObjectId) savedUser.get("_id")).toString());
    ResultVO ret = new ResultVO<>();
    ret.setCode(0);
    ret.setData(vo);
    return ret;
  }
}

处理跨域cors问题

@SpringBootApplication
@ComponentScan(basePackages = {"cloud.unionj.guide"})
public class ApiApplication {

  public static void main(String[] args) {
    SpringApplication.run(ApiApplication.class, args);
  }

  @Bean
  public CorsFilter corsFilter() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("*"));
    configuration.addAllowedHeader("*");
    configuration.addAllowedMethod("*");
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return new CorsFilter(source);
  }

}

使用ts客户端代码


准备脚手架

我们为本文准备了一个vue2+ts的脚手架工程,可直接用于项目开发

  • 克隆代码
git clone [email protected]:unionj-cloud/vue2-ts-scaffold.git guide-ui
  • 安装依赖
npm install --registry=https://registry.npm.taobao.org
  • 运行程序
yarn serve
  • 浏览器打开
image

下载客户端代码

在上文提到的网页版代码下载器上下载ts客户端代码,解压后如图:

image

services文件夹里就是封装了axios的http客户端代码。将services文件夹放入上文初始化的工程的src目录下,如图

image

组件中使用

  • 修改src/services/BizService.ts文件里serverName的值
/**
* Generated by unionj-generator.
* You can edit it as your need.
*/
import { responseUse } from "@/utils/response";

export class BizService {

  static serverName: string | undefined = process.env.VUE_APP_BIZ_SERVICE;

  axios: any;

  constructor(axios: any) {
    this.axios = axios;
    this.axios.interceptors.response.use(responseUse,null);
  }

  protected addPrefix(endpoint: string){
    if(BizService.serverName) {
      if(BizService.serverName.indexOf("/") === 0 || BizService.serverName.indexOf("http") === 0) {
        return BizService.serverName + endpoint
      }
      return "/" + BizService.serverName + endpoint
    }
    return endpoint
  }

}

export default BizService;
  • 配置guide后端接口baseUrl
VUE_APP_BIZ_SERVICE=http://localhost:8080
  • 修改src/App.vue文件

这段代码是用bootstrap写了一个table组件


这段代码首先在mounted钩子里new了一个UserService实例,我们在methods里通过this.userService来调用生成代码里的接口方法,发起http请求,获取返回值。下面的代码里以调用postApiUserPage方法为例,说明了使用方法,非常直观和简单。


通过postman准备数据

  • 注册用户
image
  • 编辑用户信息
image
  • 查看数据
image

启动项目看效果

image

总结


通过上文的讲解和效果展示,我们可以看出unionj-generator生成的typescript客户端代码是非常易用和直接的。通过在自己团队部署网页版下载器,可以轻松下载到代码,放入前端工程中使用。请点击链接查看文本中演示项目的源码。其实还有更高级的玩法,那就是写一个命令行代码下载器,写进package.json里的scripts里,通过npm scripts脚本命令来直接下载代码压缩包,解压到指定的目录。我们已经写好一个工具,已在团队中使用,介绍文章《unionj-generator快速上手-命令行客户端下载器》正在写作中...

你可能感兴趣的:(unionj-generator快速上手-前端篇)