unionj-generator快速上手-前端篇

2021-07-16  本文已影响0人  wubin1989
Photo by Proxyclick Visitor Management System

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

网页版代码下载器


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

本地开发

git clone git@github.com:unionj-cloud/unionj-generator.git
git checkout tags/v1.6.0 -b v1.6.0
mvn clean install -Dmaven.test.skip=true
git clone git@github.com:unionj-cloud/openapi-svc.git
mvn clean install -Dmaven.test.skip=true
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部署

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
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工具或者前端工程化工具

后端接口改造


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

POM

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
  <groupId>de.flapdoodle.embed</groupId>
  <artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>

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<byte[]> 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<UserDetailVO> getApiUserDetail(String id) {
    UserDetailVO vo = mongoTemplate.findById(id, UserDetailVO.class, "guide");
    ResultVO<UserDetailVO> ret = new ResultVO<>();
    ret.setCode(0);
    ret.setData(vo);
    return ret;
  }

  @SneakyThrows
  @Override
  public ResultVO<String> 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<String> ret = new ResultVO<>();
    ret.setCode(0);
    ret.setData("OK");
    return ret;
  }

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

  @Override
  public ResultVO<UserRegisterRespVO> 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<UserRegisterRespVO> 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 git@github.com: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

组件中使用

/**
* 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;
VUE_APP_BIZ_SERVICE=http://localhost:8080

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

<template>
  <div id="app">
    <h1>unionj-generator-guide frontend vue2 + typescript scaffold</h1>
    <b-table striped hover :items="data" :fields="fields" fixed>
      <template #cell(avatar)="data">
        <img :src="data.value" alt="">
      </template>
    </b-table>
  </div>
</template>

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

<script lang="ts">
import Vue from 'vue'
import axios from 'axios'
import UserService from './services/UserService'
import { ResultVOPageResultVOUserDetailVO, UserDetailVO, UserPageReqVO } from './services/types'

export default Vue.extend({
  name: 'App',
  data() {
    return {
      userService: {} as UserService,
      fields: [
        {
          key: 'id',
          label: 'ID',
        },
        {
          key: 'avatar',
          label: '头像',
        },
        {
          key: 'name',
          label: '姓名',
        },
        {
          key: 'age',
          label: '年龄',
        },
        {
          key: 'sex',
          label: '性别',
        },
      ],
      data: [] as UserDetailVO[],
    }
  },
  mounted() {
    this.userService = new UserService(axios)
    this.getAllUser()
  },
  methods: {
    getAllUser() {
      const payload = {
        size: 10,
        current: 1,
      } as UserPageReqVO
      this.userService.postApiUserPage(payload).then((resp: ResultVOPageResultVOUserDetailVO) => {
        if (resp.code === 0) {
          this.data = resp.data.items
          this.data.forEach((x) => {
            x.avatar = process.env.VUE_APP_BIZ_SERVICE + "/api/user/avatar?id=" + x.id
          })
        }
      })
    },
  },
})
</script>

通过postman准备数据

image image image

启动项目看效果

image

总结


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

上一篇 下一篇

猜你喜欢

热点阅读