一步步带你用react+spring boot搭建后台之二(登录与首页篇)

news2024/11/25 5:00:00
  • 前言


最近半年一直在重庆忙于项目上的事情,博客停更了好久,一直想写2个开源项目:

一个是入门级:一步步带你用react+spring boot搭建后台

一个是olap应用系列:一步步构建olap分析平台

今天开始写第一个系列,完整代码随后上传github

  • 登录


登录界面:

 click事件触发登录操作:

// //将store.dispatch方法挂载到props上
const mapDispatchToProps = (dispatch) => {
    return {
        login_prop(loginName, password) {
            let r= login(loginName, password).then(
                (res) => {
                    console.log("get article response:", res);
                    if (res.code === "200") {
                        let _token = res.data.token;
                        if (_token != null && _token.length > 0) {  //返回token
                            const action = {
                                type: 'login_token',
                                login_token: _token
                            }
                            //存放到cookie
                            setToken(_token)
                            dispatch(action)
                            //继续跳转......
                            this.history.push('/main')
                            return;
                        }
                        else{
                            console.log("get token failed!");
                            return -2;
                        }
                    }else{   //登录失败 用户名 密码错误 主要走这个

                        return -1;
                    }
                },
                (error) => {
                    console.log("get response failed!");
                    return -3;
                }
            );
            return r;
        }
    }
}

登录成功后,服务端会返回一个 token(该token的是一个能唯一标示用户身份的一个key),之后我们将token存储在本地cookie之中,这样下次打开页面或者刷新页面的时候能记住用户的登录状态,不用再去登录页面重新登录了。

  • 登录服务端

服务端我们用shiro实现:

shiro的结构图如下:

项目引入shiro网上教程很多,这里就不重复。

    @PostMapping("/loginPost")
    public R login(@RequestBody() IcUser user) {
        HashMap<Object, Object> map = new HashMap<>();
        Subject subject = SecurityUtils.getSubject();
        try {
            PersonnelPasswordToken token = new PersonnelPasswordToken(user);
            subject.login(token);
        } catch (Exception e) {
            return R.error(e.getCause().getMessage());
        }
        map.put("token", subject.getSession().getId());
        //basPersonnelService.clearResourceCache(UserUtil.getBasPersonnel().getGuid());
        icSecurityModule.clearResourceCache(UserUtil.getIcUser().getUserId());
        return R.ok(map);
    }

这里我写了个UserRealm 


import com.comm.cache.CacheException;
import com.comm.cache.CacheHelp;
import com.comm.cachecite.keydef.IcUserLoginName_Key;
import com.comm.common.exception.ReturnException;
import com.comm.common.utils.MD5Utils;
import com.comm.f_olap.entity.IcUser;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

public class UserRealm extends AuthorizingRealm {
    CacheHelp cacheHelp=new CacheHelp();

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        PersonnelPasswordToken token = (PersonnelPasswordToken) authenticationToken;
        String loginUserName = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        IcUser user = null;
        try {
           List  cs=cacheHelp.getAllObjectInCache(IcUser.class);
            user=(IcUser)cacheHelp.getObjectInCache(IcUser.class,new IcUserLoginName_Key(true),loginUserName);
        } catch (CacheException e) {
            e.printStackTrace();
        }
        if(user==null) throw new ReturnException("无此用户!");

        if (user == null) {
            throw new ReturnException("无此用户!");
        }

        String md5Psw = MD5Utils.encrypt(password).toUpperCase();
        if (!user.getPassword().toUpperCase().equals(md5Psw)) {
            throw new ReturnException("密码错误!");
        } else {
            logger.info("用户:{},登录成功!", loginUserName);
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
        return info;
    }

}

spring boot 通过 shiroconfig  认识相关realm

    @Bean
    public Realm realm() {
        UserRealm userRealm = new UserRealm();
        userRealm.setAuthenticationTokenClass(PersonnelPasswordToken.class);
        return userRealm;
    }

vue中用户登录成功之后,一般会在全局钩子router.beforeEach中拦截路由,判断是否已获得token,在获得token之后再去获取用户的基本信息。

react实现路由拦截一般是靠鉴权组件去实现的,在特定的模块或者最上层主模块建立一个鉴权组件,在获取到当前路由信息时,可以先判断权限是否通过,不通过则不渲染children,用路由重定向至特定页面,否则渲染children。

    componentDidMount() {
        getMenus().then(
            (res) => {
                if( res.code == 501 ){
                    //没有登录 跳转到登录页面
                    this.props.history.push("/login")
                    return
                }
                console.log(res.data[0].children);
                this.setState({menus: res.data[0].children});
            },
            (error) => {
                console.log("get getMenus failed!");
            }
        );
    }

就如前面所说的,我只在本地存储了一个用户的token,并没有存储别的用户信息(如用户权限,用户名,用户头像等)。有些人会问为什么不把一些其它的用户信息也存一下?主要出于如下的考虑:

假设我把用户权限和用户名也存在了本地,但我这时候用另一台电脑登录修改了自己的用户名,之后再用这台存有之前用户信息的电脑登录,它默认会去读取本地 cookie 中的名字,并不会去拉去新的用户信息。

正常情况下 获取用户信息和获取角色权限信息应该分为2个办法,我这里都是通过getMenus方法实现的。

    @GetMapping("/getMemus")
    public R getMemus(){
        IcUser user=UserUtil.getIcUser();
        Integer userId=user.getUserId();
        //Integer userId=21001;
        //根据userId 查找对应的role
        //IcUserRole userRole=null;
        try {
           List<IcUserRole>  userRoles=(List<IcUserRole>) cacheHelp.getObjectInCache(IcUserRole.class,new IcRole_by_userId_Key(false),userId);
        if(userRoles!=null && userRoles.size()>0){
            IcUserRole userRole=userRoles.get(0);
            Integer roleId=userRole.getId().getRoleId();
            //根据roleId 查找角色
           // IcRole role=(IcRole)cacheHelp.getObjectInCache(IcRole.class,new IcRole_PK(true),roleId);
            //根据role查询function
            List<IcRoleFunction> icRoleFunctions=(  List<IcRoleFunction>)cacheHelp.getObjectInCache(IcRoleFunction.class,new IcRoleFunction_by_roleId_Key(false),roleId);
            List<SysResource> functions=new ArrayList<SysResource>();
            if(icRoleFunctions!=null && icRoleFunctions.size()>0){
                icRoleFunctions.forEach((IcRoleFunction rf)->{
                   Integer functionId= rf.getFunctionId();
                    SysResource function=null;
                    try {
                         function=(SysResource)cacheHelp.getObjectInCache(SysResource.class,new IcSysResource_Key(true),functionId);
                        functions.add(function);
                    } catch (CacheException e) {
                        e.printStackTrace();
                    }
                });
            }

            List<Tree<SysResource>> trees = new ArrayList<Tree<SysResource>>();
            //resourceOrder
            //functions.sort();
            //Collections.sort(functions,(s1, s2) ->);
            functions.sort(Comparator.comparing(SysResource::getPosition));

            for (int i = 0; i < functions.size(); i++) {
                SysResource sysResource = functions.get(i);
                Tree<SysResource> tree = new Tree<SysResource>();
                tree.setKey(sysResource.getId());
                tree.setId(sysResource.getId()+"");
                tree.setParentId(sysResource.getParentId()+"");
                tree.setText(sysResource.getResourceName());
                tree.setTitle(sysResource.getResourceName());
                tree.setPath(sysResource.getResourceUrl());
                tree.setIcon(sysResource.getIcon());
                trees.add(tree);
            }
            List<Tree<SysResource>> functionTrees = BuildTree.buildList(trees,"-1");
            return R.ok(functionTrees);
        }
        } catch (CacheException e) {
            e.printStackTrace();
        }
        //role  获取functions
        //组装成数据
        return R.ok();
    }
  • 首页


登录后跳转到的首页如下:

import React from 'react';
import ReactDOM from 'react-dom';
import {
    BrowserRouter as Router,
    Switch,
    Route,
    Link,
    useParams,
    useRouteMatch
} from "react-router-dom";
import 'antd/dist/antd.css';
import './base.css';
import {Layout, Menu, Row, Col, Button} from 'antd';
import {
    MenuUnfoldOutlined,
    MenuFoldOutlined,
    UserOutlined,
    VideoCameraOutlined,
    UploadOutlined,
    TagOutlined
} from '@ant-design/icons';
import ReportType from '../views/reportType.js';
import UserList from '../views/userList.js';
import RoleList from '../views/roleList.js';
import UserRole from '../views/userRole.js';
import Resource from '../views/resource.js'
import ManageReport from '../views/manageReport.js';
import MainConntent from '../views/mainConntent.js';
import DimManagement from "../views/DimManagement";
import FormManagement from "../views/formManagement";
import ProcessManage from "../views/processManage.js"
import ProcessDef from "../views/processDef.js"
import  ProcessDefView from "../views/ProcDefView.js"
import HeaderBar from "./headerBar"
import AsideMenu from "./AsideMenu";
import {getMenus} from "../api/Security";
import  WorkflowDesign from '../views/workflowDesign.js'
import  ProcDefView from '../views/ProcDefView.js'
import DataSource from "../views/dataSource";
import CodeMapping from '../views/codeMapping.js'
import ReadExcel from '../views/readExcel.js'
import QueryAccount from '../views/queryAccount.js'
import RunSql from '../views/runSql.js'
import Dynamic_Form_Designer from '../views/dynamic_form_designer.js'
import Dynamic_Form_Designer2 from '../views/dynamic_form_designer2.js'
import Account_report from '../views/Account_report.js'
import CaDataObject from '../views/caDataObject.js'
import AnalyzerFolder from '../views/analyzerFolder.js'
import CaAnalysisManage from '../views/caAnalysisManage.js'
const { Header, Sider, Content } = Layout;
export  default  class MainContent extends React.Component {
    state = {
        collapsed: false,
        menus:[]
    };
    toggle = () => {
        this.setState({
            collapsed: !this.state.collapsed,
        });
    };
    componentDidMount() {
        getMenus().then(
            (res) => {
                if( res.code == 501 ){
                    //没有登录 跳转到登录页面
                    this.props.history.push("/login")
                    return
                }
                console.log(res.data[0].children);
                this.setState({menus: res.data[0].children});
            },
            (error) => {
                console.log("get getMenus failed!");
            }
        );
    }
    render() {
        console.log(this.state.menus);
        return (
            <Layout id="mainLayout" className="main">
                <Sider trigger={null} collapsible collapsed={this.state.collapsed}
                       style={{flex:1}}
                >
                    {/*<div className="logo" />*/}
                    <AsideMenu  menus={this.state.menus}/>
                </Sider>
                <Layout className="site-layout"  style={{flex:1}}>
                    <Header className="site-layout-background" style={{ padding: 0 }}>
                        <Row>
                            <Col span={22}>
                                {React.createElement(this.state.collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
                                className: 'trigger',
                                onClick: this.toggle,
                                 })}
                            </Col>
                            <Col span={2}>
                                <HeaderBar/>
                            </Col>
                        </Row>
                    </Header>
                    <Content
                        className="site-layout-background"
                        style={{
                            margin: '24px 16px',
                            padding: 24,
                            minHeight: 280,
                            flex: 1,
                            display: 'flex',
                            flexDirection: 'column'
                        }}
                    >
                        {/*内容区域*/}
                        {/*<Route exact path="/reportTypes" component={ReportType} />*/}

                        <Switch>
                            <Route exact path="/main/base/reportType">
                                <ReportType />
                            </Route>
                            <Route exact path="/main/base/datasource">
                                <DataSource />
                            </Route>
                            <Route path="/main/report/finance">
                                <ManageReport/>
                            </Route>
                            <Route path="/main/olap/dim">
                                <DimManagement/>
                            </Route>
                            <Route path="/main/olap/form">
                                <FormManagement/>
                            </Route>
                            <Route path="/main/secrity/userList">
                                <UserList/>
                            </Route>
                            <Route path="/main/secrity/role">
                                <RoleList/>
                            </Route>
                            <Route path="/main/secrity/resource">
                                <Resource/>
                            </Route>
                            <Route path="/main/secrity/userRole">
                                <UserRole/>
                            </Route>
                            <Route path="/main/COLLECTION_DATA/RUN_SQL">
                                <RunSql/>
                            </Route>
                            <Route path="/COLLECTION_DATA/RUN_SQL">
                                <UserList/>
                            </Route>
                            <Route path="/main/tool/processManage">
                                <ProcessManage/>
                            </Route>
                            <Route path="/main/tool/processDef">
                                <ProcessDef/>
                            </Route>
                            <Route exact  path="/main/tool/viewProcDef/:procId"  component={ProcessDefView}/>
                            <Route  path="/main/tool/newDesigner">
                                <WorkflowDesign/>
                            </Route>
                            <Route  path="/main/dataTool/codeMapping">
                                <CodeMapping/>
                            </Route>
                            <Route  path="/main/dataTool/readExcel">
                                <ReadExcel/>
                            </Route>
                            <Route  path="/main/dataTool/queryAccount">
                                <QueryAccount/>
                            </Route>
                            <Route  path="/main/dynamicForm/formDesigner">
                                <Dynamic_Form_Designer/>
                            </Route>
                            <Route  path="/main/dynamicForm/formDesigner2">
                                <Dynamic_Form_Designer2/>
                            </Route>
                            <Route  path="/main/account_report">
                                <Account_report/>
                            </Route>
                            <Route  path="/main/analyzer/DataObject">
                                <CaDataObject/>
                            </Route>
                            <Route  path="/main/analyzer/analyzerFolder">
                                <AnalyzerFolder/>
                            </Route>
                            <Route  path="/main/analyzer/DataObject">
                                <CaDataObject/>
                            </Route>
                            <Route  path="/main/analyzer/AnalysisManage">
                                <CaAnalysisManage/>
                            </Route>
                        </Switch>
                    </Content>
                </Layout>
            </Layout>
        );
    }
}


左边是菜单,右边为内容区,右边路由 switch,是否应该根据后台数据循环构建呢?现在这种写法,后台动态增加菜单栏目的时候,还需要配套修改这个switch的内容啊。

路由体系,由路由地图、link和对应的组件三部分组成,下面我们描述link的构建,动态渲染菜单。

  • 动态渲染菜单

    当前,我们从后端根据用户角色查询到可以访问的菜单数据,传递到前端,前端根据后台的菜单数据,动态渲染左边导航菜单,

从后端返回的菜单信息,包括菜单名称、key等,;另外包括path信息,这个和路由是对应的,当用户点击菜单的时候,即link关联的路由,

{
    "key":0,
    "id":"0",
    "text":"全部",
    "title":"全部",
    "alias":null,
    "path":"/main",
    "position":0,
    "state":null,
    "checked":false,
    "attributes":null,
    "children":[
        {
            "key":1,
            "id":"1",
            "text":"基础资料",
            "title":"基础资料",
            "alias":null,
            "path":"/main/base",
            "position":0,
            "state":null,
            "checked":false,
            "attributes":null,
            "children":[
                Object{...},
                {
                    "key":12,
                    "id":"12",
                    "text":"数据源",
                    "title":"数据源",
                    "alias":null,
                    "path":"/main/base/datasource",
                    "position":0,
                    "state":null,
                    "checked":false,
                    "attributes":null,
                    "children":null,
                    "parentId":"1",
                    "hasParent":true,
                    "hasChildren":false,
                    "icon":null,
                    "btn":false,
                    "menuId":null,
                    "type":null,
                    "ftype":0,
                    "levelnum":0
                }
            ],
            "parentId":"0",
            "hasParent":true,
            "hasChildren":true,
            "icon":null,
            "btn":false,
            "menuId":null,
            "type":null,
            "ftype":0,
            "levelnum":0
        },
        {
            "key":3,
            "id":"3",
            "text":"财务报表",
            "title":"财务报表",
            "alias":null,
            "path":"/main/report/",
            "position":0,
            "state":null,
            "checked":false,
            "attributes":null,
            "children":[
                {
                    "key":31,
                    "id":"31",
                    "text":"报表模板",
                    "title":"报表模板",
                    "alias":null,
                    "path":"/main/report/finance",
                    "position":0,
                    "state":null,
                    "checked":false,
                    "attributes":null,
                    "children":null,
                    "parentId":"3",
                    "hasParent":true,
                    "hasChildren":false,
                    "icon":null,
                    "btn":false,
                    "menuId":null,
                    "type":null,
                    "ftype":0,
                    "levelnum":0
                },
                ......
    ],
    "parentId":"-1",
    "hasParent":false,
    "hasChildren":true,
    "icon":null,
    "btn":false,
    "menuId":null,
    "type":null,
    "ftype":0,
    "levelnum":0
}

我们根据后台取得的菜单数据渲染前端菜单,代码如下:

import React, { Component,Fragment } from 'react'
import {Link,withRouter} from 'react-router-dom'
import {  Menu } from 'antd';
import {
    TagOutlined
} from '@ant-design/icons';
const { SubMenu } = Menu;

class AsideMenu extends Component {
    constructor(props) {
        super(props);
        this.state= {
            selectedKeys:[],   //selectedKeys 当前选中的菜单项 key 数组
            openKeys:[],   //openKeys, 当前展开的 SubMenu 菜单项 key 数组
            menus:this.props.menus
        }
    }
    componentDidMount(){
        const pathname = this.props.location.pathname;
        const menukey = pathname.split("/").slice(0,3).join('/');
        const menuHigh = {
            selectedKeys: pathname,
            openKeys: menukey
        }
        this.selectMenuHigh(menuHigh)
    }
    selectMenu =({item,key,keyPath}) => {
        // 选中菜单
        const menuHigh = {
            selectedKeys: key,
            openKeys: keyPath[keyPath.length - 1]
        }
        this.selectMenuHigh(menuHigh)
    }
    openMenu = (openKeys) => {
        // 展开
        this.setState({
            openKeys: [openKeys[openKeys.length - 1]]
        })
    }
    selectMenuHigh = ({selectedKeys,openKeys}) => {
        // 菜单高亮
        this.setState({
            selectedKeys: [selectedKeys],
            openKeys: [openKeys]
        })
    }
    // 处理一级菜单栏
    renderMenu =({title,key,path, text}) => {
        return (
            <Menu.Item key={key}  icon={<TagOutlined/>}>
                <Link to={path}>
                    <span>{text}</span>
                </Link>
            </Menu.Item>
        )
    }
    // 处理子级菜单栏
    renderSubMnenu = ({text,key,children}) => {
        return (
            <SubMenu key={key} title={text}>
                {
                    children && children.map(item => {
                        return item.children && item.children.length > 0 ? this.renderSubMnenu(item) : this.renderMenu(item)
                    })
                }
            </SubMenu>
        )

    }
    render() {

        let Router2= this.props.menus || [];
        const { selectedKeys,openKeys } = this.state
        //debugger
        return (
            <Fragment>
                <Menu
                    onOpenChange={this.openMenu}
                    onClick={this.selectMenu}
                    theme="dark"
                    mode="inline"
                    selectedKeys={selectedKeys}
                    openKeys={openKeys}
                    style={{ height: '100%', borderRight: 0 }}
                >
                    {
                        Router2 && Router2.map(firstItem => {
                            return firstItem.children && firstItem.children.length > 0 ? this.renderSubMnenu(firstItem) : this.renderMenu(firstItem)
                        })
                    }
                </Menu>
            </Fragment>
        )
    }
}
export default withRouter(AsideMenu)
  • 路由
//引入react jsx写法的必须
import React from 'react';
//引入需要用到的页面组件
import Home from './pages/home';
import About from './pages/about';
import Designer from './pages/designer';
import Login from './base/login'
import MainContent from './base/main'
import EditReport from './views/editReport'
import EditReport_Grid from './views/editReport_Grid'

import ViewReport from './views/viewReport'
import DimManagement from './views/DimManagement'
import FormManagement from './views/formManagement'
import ViewForm from './views/ViewForm'
import TestDiv from './views/testDiv'
//引入一些模块
import { BrowserRouter as Router, Route,Switch} from "react-router-dom";

function router(){
    return <Router>
                <Switch>
                    <Route key="/home" path="/home"  component={Home} />
                    <Route key="/designer" path="/designer" component={Designer} />
                    <Route key="/about" path="/about" component={About} />
                    <Route key="/login" path="/login" component={Login} />
                    <Route key="/mainKey" path="/main" component={MainContent} />
                    {/*<Route key="/main2"  component={SiderDemo2} />*/}
                    <Route key="/eidtReport/id" path="/eidtReport/:id" component={EditReport} />
                    <Route key="/eidtReportGrid/id" path="/eidtReportGrid/:id" component={EditReport_Grid} />
                    <Route key="/viewReport/id"  path="/viewReport/:id/:accountSetId/:year/:month/:orgName/:reportDate/:reportNo/:lister/:auditor/:way/:reportInstanceId" component={ViewReport} />
                    {/*<Route path="/login" component={LoginForm} />*/}
                    <Route key="/dim" path="/dim" component={DimManagement} />
                    <Route key="/formManagement" path="/formManagement" component={FormManagement} />
                    <Route key="/viewForm/formId" path="/viewForm/:formId" component={ViewForm} />
                    <Route key="/testdiv" path="/testdiv" component={TestDiv} />
                </Switch>
            </Router>
}

export default router;

App.js当代代码:

import React from 'react';
import Router from './Router'
class App extends React.Component {
    render(){
        return (
            <Router />
        );
    }
}
export default App;
  • 每次请求带token

我们对每一个请求都会验证权限,所以这里我们针对业务封装了一下请求。首先我们通过request拦截器在每个请求头里面塞入token,好让后端对请求进行权限验证。

/**
 * 网络请求配置
 */
import axios from "axios";
import  store from '../store/store'
import { getToken } from './auth'
//store.getState()
axios.defaults.timeout = 200000;
axios.defaults.baseURL = "/reportapi/report";
/**
 * http request 拦截器
 */
axios.interceptors.request.use(
    (config) => {

        if (store.getState().login_token) {
            //为什么从cookie当中取这个值呢?从state当中取得不好吗
            config.headers['X-Token'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
        }
        // showFullScreenLoading()
       // startLoading()
        console.log("getToken():"+getToken());
        console.log("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$:"+store.getState().login_token)
        // config.data = JSON.stringify(config.data);
        // config.headers = {
        //     "Content-Type": "application/json",
        // };
        return config;
    },
    (error) => {
        return Promise.reject(error);
    }
);

/**
 * http response 拦截器
 */
axios.interceptors.response.use(
    (response) => {
        if (response.data.errCode === 2) {
            console.log("过期");
        }
        return response;
    },
    (error) => {
        console.log("请求出错:", error);
    }
);

/**
 * 封装get方法
 * @param url  请求url
 * @param params  请求参数
 * @returns {Promise}
 */
export function get(url, params = {}) {
    return new Promise((resolve, reject) => {
        axios.get(url, {
            params: params,
        }).then((response) => {
            //landing(url, params, response.data);
            console.log("http  response in axios:"+response)
            resolve(response.data);
        })
            .catch((error) => {
                console.log("http  error in axios:"+error)
                reject(error);
            });
    });
}

/**
 * 封装post请求
 * @param url
 * @param data
 * @returns {Promise}
 */

export function post(url, data) {
    return new Promise((resolve, reject) => {
        axios.post(url, data).then(
            (response) => {
                //关闭进度条
                resolve(response.data);
            },
            (err) => {
                reject(err);
            }
        );
    });
}

/**
 * 封装patch请求
 * @param url
 * @param data
 * @returns {Promise}
 */
export function patch(url, data = {}) {
    return new Promise((resolve, reject) => {
        axios.patch(url, data).then(
            (response) => {
                resolve(response.data);
            },
            (err) => {
                msag(err);
                reject(err);
            }
        );
    });
}
/**
 * 封装put请求
 * @param url
 * @param data
 * @returns {Promise}
 */
export function put(url, data = {}) {
    return new Promise((resolve, reject) => {
        axios.put(url, data).then(
            (response) => {
                resolve(response.data);
            },
            (err) => {
                msag(err);
                reject(err);
            }
        );
    });
}
//统一接口处理,返回数据
export default function (fecth, url, param) {
    let _data = "";
    return new Promise((resolve, reject) => {
        switch (fecth) {
            case "get":
                console.log("begin a get request,and url:", url);
                get(url, param)
                    .then(function (response) {
                        resolve(response);
                    })
                    .catch(function (error) {
                        console.log("get request GET failed.", error);
                        reject(error);
                    });
                break;
            case "post":
                post(url, param)
                    .then(function (response) {
                        resolve(response);
                    })
                    .catch(function (error) {
                        console.log("get request POST failed.", error);
                        reject(error);
                    });
                break;
            default:
                break;
        }
    });
}
//失败提示
function msag(err) {
    if (err && err.response) {
        switch (err.response.status) {
            case 400:
                alert(err.response.data.error.details);
                break;
            case 401:
                alert("未授权,请登录");
                break;

            case 403:
                alert("拒绝访问");
                break;

            case 404:
                alert("请求地址出错");
                break;

            case 408:
                alert("请求超时");
                break;

            case 500:
                alert("服务器内部错误");
                break;

            case 501:
                alert("服务未实现");
                break;

            case 502:
                alert("网关错误");
                break;

            case 503:
                alert("服务不可用");
                break;

            case 504:
                alert("网关超时");
                break;

            case 505:
                alert("HTTP版本不受支持");
                break;
            default:
        }
    }
}
/**
 * 查看返回的数据
 * @param url
 * @param params
 * @param data
 */
function landing(url, params, data) {
    if (data.code === -1) {
    }
}

上面对后端请求也进行了简单封装。

  • 首页布局(待续)
  • permission (待续)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/52487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LDO(线性稳压器)设计检查

原理图设计规范检查——LDO&#xff08;线性稳压器&#xff09;设计检查 LDO基本概念&#xff1a; LDO即low dropout regulator&#xff0c;是一种低压差线性稳压器&#xff0c;这是相对于传统的线性稳压器来说的。传统的线性稳压器&#xff0c;如78XX系列的芯片都要求输入电…

Linux cifs挂载远程windows共享目录

Linux cifs挂载远程windows共享目录共享windows目录开启共享权限共享磁盘或目录Linux 先决条件安装Linux依赖开启Administrator 用户使用Username/Password挂载临时挂载自动挂载使用Credentials挂载创建CIFS Windows共享凭证文件临时挂载自动挂载终止挂载共享windows目录 开启…

“算力时代”奔涌而来,JASMINER茉莉发布能效更强劲的X16-Q

11月26日&#xff0c;JASMINER茉莉发布X16系列首款静音型算力产品X16-Q&#xff0c;并同步开启全球预售&#xff0c;将为行业带来更高效、更绿色、更智能的智慧算力。 JASMINER X16相较X4系列产品迎来了全新的“进化”&#xff0c;除去新一代JASMINER茉莉自研高通量芯片的应用…

百看不如一练系列 32个python实战项目列表,得不到就毁掉

前言&#xff1a; 不管学习哪门语言都希望能做出实际的东西来&#xff0c;这个实际的东西当然就是项目啦&#xff0c;不用多说大家都知道学编程语言一定要做项目才行。 这里整理了32个Python实战项目列表&#xff0c;都有完整且详细的教程&#xff0c;你可以从中选择自己想做…

Day2多种抓包工具介绍以及使用封包监听工具找到挑战数据包实现发送数据包进行挑战

工具相关证书安装指南 Charles https://blog.csdn.net/weixin_45459427/article/details/108393878 Fidder https://blog.csdn.net/weixin_45043349/article/details/120088449 BurpSuite https://blog.csdn.net/qq_36658099/article/details/81487491 Fiddler&#xff1a; 是一…

PyQt5 不规则窗口的显示

PyQt5 不规则窗口的显示QPixmap和QBitmap绘图的效果对比不可以拖动的不规则窗口可以拖动的不规则窗口不规则窗口实现动画效果加载GIF动画效果函数描述setMask(self, QBitmap)setMask(self, QRegion)setMask()的作用是为调用它的控件增加一个遮罩&#xff0c;遮住所选区域以外的…

【Android App】实战项目之仿微信的附近的人(附源码和演示 超详细)

需要全部源码请点赞关注收藏后评论区留言私信~~~ 艺术家常说“距离产生美”&#xff0c;其实距离近才是优势&#xff0c;谁不希望自己的工作事少钱多离家近呢&#xff1f;不光是工作&#xff0c;像租房买房、恋爱交友&#xff0c;大家都希望找个近点的&#xff0c;比如58、赶集…

【react-笔记】

目录简介基本使用虚拟dom的两种创建方法jsx语法规则模块与组件、模块化和组件化的理解模块组件模块化组件化函数式组件类式组件组件实例三大属性statepropsrefs事件处理包含表单的组件分类非受控组件受控组件高阶函数_函数的柯里化生命周期引出生命周期理解生命周期(旧)总结新的…

Verilog 延迟反标注

延迟反标注&#xff0c; SDF 延迟反标注是设计者根据单元库工艺、门级网表、版图中的电容电阻等信息&#xff0c;借助数字设计工具将延迟信息标注到门级网表中的过程。利用延迟反标注后的网表&#xff0c;就可以进行精确的时序仿真&#xff0c;使仿真更接近实际工作的数字电路…

当MySQL想恋爱,java和navicate抢着做媒婆 ------ java连接MySQL数据库 navicat for MySQL 连接

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 **收录于专栏 数据库 ⭐当MySQL和java通过媒婆navicate谈上了恋爱⭐ 文章目录⭐当MySQL和java通过媒婆navicate谈上了恋爱…

Linux 多线程

目录 一.线程概念 1.什么是线程 2.页表 &#xff08;1&#xff09;页表结构 &#xff08;2&#xff09;好处 3.线程优点 4.线程缺点 5.线程异常 6.线程用途 7.进程和线程的 8.简单使用线程 二.线程控制 1.使用线程 2.线程栈和pthread_t 3.线程的局部存储 4.分离…

[附源码]计算机毕业设计springboot室内设计类网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

R语言中的划分聚类模型

划分聚类 是用于基于数据集的相似性将数据集分类为多个组的聚类方法。我们围绕聚类技术进行一些咨询&#xff0c;帮助客户解决独特的业务问题。 【视频】KMEANS均值聚类和层次聚类&#xff1a;R语言分析生活幸福质量系数可视化实例 KMEANS均值聚类和层次聚类&#xff1a;R语言分…

GUI自动化测试工具Sikulix的安装和使用

从程序内部控制对小白来说太难了&#xff0c;所以使用一下自动化测试的工具直接控制按钮达到我的目的 一个比较好的自动化测试工具是Sikulix&#xff0c;这里记录一下安装和基本的使用 下载和安装 官网&#xff1a;http://www.sikulix.com/ 下载对应系统的.jar需要使用java&…

第二证券|A股集体收涨,汽车产业链爆发!房地产延续强势

11月30日早盘&#xff0c;A股三大指数小幅上行。到午间收盘&#xff0c;沪指涨0.21%报3156.50点&#xff0c;深成指涨0.38%&#xff0c;创业板指涨0.20%&#xff1b;两市算计成交5692亿元。 盘面上看&#xff0c;轿车、燃气、地产、油气、煤炭等板块走强&#xff0c;酒店餐饮、…

实验室信息化建设的意义

实验室信息管理系统将实验室的仪器设备、实验人员、实验环境以及相关数据进行集成和管理&#xff0c;使整个实验室形成一个有机整体&#xff0c;规范了业务流程和管理体制&#xff0c;实现各部门之间资源共享协同作业&#xff0c;达到优化配置资源和提高工作效率&#xff0c;不…

欧洲肿瘤生物学博士后申请经历

国外博士后的申请者经常会遇到各种问题&#xff0c;从而感叹申请过程的不易。知识人网小编推荐这篇申请经历&#xff0c;或许会给其他申请者带来一定启示。 作者从今年1月开始申请&#xff0c;5月份获得offer。以下是原文&#xff1a; 背景介绍&#xff1a;国内双非一本生物工…

云开发静态网站H5跳转小程序(记录过程)以及云环境共享(同一主体)

需求&#xff1a;老板要求是在H5网页端&#xff0c;无论是在微信浏览器还是在微信外部浏览器都可以打开这个H5之后&#xff0c;然后跳转到小程序上。 查看了微信相关的文档&#xff0c;发现H5端跳转小程序是有两种方式&#xff1a; 一&#xff1a;微信内网页跳转小程序 官方文档…

【春秋云境】CVE-2022-24124复现

一直不明白updatexml到底要怎么注入 &fieldupdatexml(0,concat(0x7e,(version()),0x7e),0) 确实可以出来版本号 但是如果换成database()还是不行 最后还是靠了大佬 http://eci-2ze625l338u3rfrh3r36.cloudeci1.ichunqiu.com:8000/api/get-organizations?p123&page…

只要让我戴上面具 , 我就会马上逃跑 ! 等下眼镜卡住了

郑重声明 : 本文不包含任何广告 , 不构成任何购买建议 , 我也强烈不建议购买本文这款产品 , 所有图片来自我手机拍照 , 如有侵权 , 通知我 , 马上删除 写在前面 相信各位同学一定都经历过火灾安全知识培训吧 而且肯定有一部分人是那种充当表演对象的上手使用过灭火器的人 除了…