首先先了解一下前端管理后台接口的架构设计流程,技术选型后端要使用Swagger接口管理,前端React使用Redux状态管理,React-redux状态映射组件Props,Redux-thunk支持异步管理状态,解析Swagger需要用到Handlebars模板编译和fs文件解析。


lua代码如何区分前端和后端_lua代码如何区分前端和后端


1、引入swagger。

后台接口服务器引入swagger。这一步就不多说了,你有我有全都有啊,诶嘿,诶嘿,参北斗啊。

2、解析swagger生成controller。

可以通过js写一个脚本生成指定格式的js文件。swagger提供的v2/api-docs网址可以访问接口的json。这个json是一个固定格式的字符串,包含tags数组和path对象。通过Handlebars模板编译和fs文件解析生成以下格式的js文件,每个类对应一个文件。同时生成一个index.js入口文件,将所有的controller文件集中装饰处理。

export default{      actions: {            findById : {                  summary: '按主键查询',                  method: 'get',                  url: (payload) => `/api/user/${payload.id}`,                  parameters: [{'name':'id','in':'path','description':'id','required':true,'type':'string'}],           },     },}

3、为每个controller文件生成对应的actions和reducers函数。

上述所说的入口文件index.js用来装饰每一个controller,装饰的内容就是遍历controller文件的actions对象,生成actions函数和reducers纯函数。最后将生成的reducers交给redux管理,actions则为组件提供调用。actions函数里面有三步,包括请求前,请求中和请求后对状态的处理。这三步是为了设置接口请求的loading状态,通过loading状态来处理页面的加载效果,省去在组件中自定义的逻辑判断。下图为每个接口在action函数的数据处理。


lua代码如何区分前端和后端_封装_02


生成action和reducer的代码:

export default (name, controller) => {      const defaultState = (type) => ({//设置请求前的数据状态,生成reducer时使用           type: type,            loading: false,            error: null,            request: null,            data: {},      })      const start_request = (type) => ({//设置开始请求的数据状态           type: type,            loading: true,            error: null,            request: null,            data: {},      })      let actions = {}      let reducers = {}    //遍历生成的controller文件的actions      _.forEach(_.keys(controller.actions), key => {            const action = controller.actions[key]            //生成action            actions[`${name}_${key}`] = (payload) => {                  return async (dispatch) => {                        //设置开始请求的数据状态                        dispatch(start_request(`${name}_${key}`))                        //开始网络请求                       let resp = {}                        try {                              resp = await ajaxUtil.myRequest(action, payload)                        } catch (e) {                              resp = e                }                        let handleResult = null                       //数据处理,这里对resp.status状态码为400-500的错误处理,和200-300的成功数据处理                        if (!resp) {                              handleResult = {                                    type: `${name}_${key}`,                                   loading: false,                                  error: '系统错误',                                  data: null,                              }                       } else if (resp.status >= 400 && resp.status < 500) {                              handleResult = {...}                                         } else if (resp.status >= 500) {                                              handleResult = {...}                                                          } else if (resp.status >= 200 && resp.status < 300) {                                                               handleResult = {                                                                     type: `${name}_${key}`,                                                                     loading: false,                                                                     error: null,                                                                     request: payload,                                                                      data: resp.data,                                                                }                                                          }                                           //请求结束数据状态处理                                           dispatch(handleResult)                                           return handleResult                                    }                }                //生成reducer                reducers[`${name}_${key}`] = (state = defaultState(`${name}_${key}`), action) => {                      if (action.type === `${name}_${key}`) {                            return {...state, ...action}                      } else {                            return state                      }                }          })          return {...actions, reducers}    }

4、封装高阶组件,将接口请求状态数据映射到组件的props中。

vuex里面有四个辅助函数这个react-redux要登场了。react-redux提供了一个connect,它是一个高阶组件,接收 React 组件作为输入,输出一个新的 React 组件。高阶组件让代码更具有复用性、逻辑性与抽象特征。可以对 render 方法作劫持,也可以控制 props 与 state。我们这里需要自己封装一个高阶组件,里面调用react-redux提供的connect函数将state和dispatch映射到组件的props,此外还需要定义两个函数映射到props中,一个是用于调用接口的函数,另一个是获取请求接口的loading状态函数。最后返回一个新的组件。

高阶组件封装如下:

export default function connect(states = null, dispatches = null) {      return (WrappedComponent) => {            const mapStateToProps = state => {                  //该函数用于获取网络请求的loading,用于组件显示加载中的指示                  const loading = (scope) => {                        return state[`${scope.controller}_${scope.method}`].loading                  }                 return states ? {...state, ...states(state), loading} : {...state, loading}            }            //集中处理请求发送的异常            const error = (cbData) => {                  //判断cbData.error,用来alert()提示用户错误信息            }            const mapDispatchToProps = dispatchAsync => {                  //该函数用于组件中发起网络请求                 const dispatch = async (scope, payload) => {                       const controller = Controller[scope.controller]                        let cbData = await dispatchAsync(controller[`${scope.controller}_${scope.method}`](payload))                        error(cbData)                        return cbData                  }                  return dispatches ? {...dispatches(dispatchAsync), dispatch} : {dispatch}           }            //reduxConnect是react-redux提供的,原名称是connect,我这里起了个别名,为了避免和我封装的高阶组件名冲突            //import {connect as reduxConnect} from 'react-redux'            const Root = reduxConnect(mapStateToProps, mapDispatchToProps)(WrappedComponent)            return class HOC extends React.Component {                  render() {                       return                   }            }     }}

5、组件引用自定义的高阶组件

如果组件涉及到网络请求,可以引入。引入之后像这样:

export default connect(mapStateToProps, mapDispatchToProps)(Home),其中Home是组件,mapStateToProps和mapDispatchToProps是想要指定映射哪些数据到props中,可以不传。