一、前端
1)目录结构

配置文件
.umirc.ts

import { defineConfig } from 'umi';
const path = require('path');
export default {// layout:{},dva: {},//约定式404404: true,base: '/myapp/',title: '我的应用',hash: true, // 清除缓存publicPath: '/myapp/',// history: {type:'hash'},nodeModulesTransform: {type: 'none',},alias: {utils: path.resolve(__dirname, 'src/utils'),},// links: [//   { rel: 'icon', href: '<%= PUBLIC_PATH %>static/favico.png' },// ],// 去除配置则约定式路由// routes: [//   { path: '/', component: '@/pages/index/Home' },//   { path: 'myApp/register/',title:'注册', component: '@/pages/index/Register' },//   { path: '/myApp/noteList',title:'记事本', component: '@/pages/page01/NoteList' },//   { path: '/myApp/note',title:'记事本', component: '@/pages/page02/Note' },//   { path: '/myApp/xianyu',title:'闲鱼', component: '@/pages/xianyu/Page01' },//   { path: '/myApp/xianyu/goodDetail',title:'商品详情', component: '@/pages/xianyu/GoodDetail/GoodDetail' },//   { path: '/myApp/xianyu/good',title:'商品详情', component: '@/pages/xianyu/GoodList/Good' },//   { path: '/myApp/users',title:'用户列表', component: '@/pages/users/index' },// ],fastRefresh: {},proxy: {'/app': {target: 'http://192.168.56.1',changeOrigin: true,pathRewrite: { '^/app': '/app' },},},
};

package.json

{"private": true,"scripts": {"start": "umi dev","build": "umi build","postinstall": "umi generate tmp","prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'","test": "umi-test","test:coverage": "umi-test --coverage"},"gitHooks": {"pre-commit": "lint-staged"},"lint-staged": {"*.{js,jsx,less,md,json}": ["prettier --write"],"*.ts?(x)": ["prettier --parser=typescript --write"]},"dependencies": {"@umijs/preset-react": "1.x","antd-mobile": "latest","qs": "^6.10.1","umi": "^3.4.8"},"devDependencies": {"@types/react": "^17.0.0","@types/react-dom": "^17.0.0","@umijs/test": "^3.4.8","axios": "^0.21.1","lint-staged": "^10.0.7","prettier": "^2.2.0","react": "17.x","react-dom": "17.x","typescript": "^4.1.2","yorkie": "^2.0.0"}
}

2)弹窗组件UserModal.tsx

import React, { useEffect } from 'react';
import { Modal,Form,Input} from 'antd';const UserModal = (props) => {const [form] = Form.useForm();const {visible,onFinish,record,userNameDisable} = props;useEffect(()=>{form.setFieldsValue(record);},[props.visible]);const layout = {labelCol: { span: 6 },wrapperCol: { span: 16 },};const onOk= ()=>{form.submit();};return (<div><Modaltitle="Basic Modal"visible={visible}onOk={onOk}onCancel={props.cancelClose}forceRender><Form {...layout}name="basic"form = {form}onFinish={onFinish}><Form.Itemlabel="用户名"name="userName"><Input disabled={userNameDisable} /></Form.Item><Form.Itemlabel="密码"name="password"rules={[{ required: true, message: 'Please input your password!' }]}><Input.Password /></Form.Item><Form.Itemlabel="邮箱"name="email"rules={[{ required: true, message: 'Please input your email!' }]}><Input /></Form.Item><Form.Itemlabel="年龄"name="age"rules={[{ required: true, message: 'Please input your name!' }]}><Input /></Form.Item><Form.Itemlabel="住址"name="address"rules={[{ required: true, message: 'Please input your username!' }]}><Input /></Form.Item><Form.Itemlabel="个性标签"name="tags"rules={[{ required: true, message: 'Please input your username!' }]}><Input /></Form.Item></Form></Modal></div>)
};export default UserModal;

index.tsx

import { Table, Tag, Space, Button,Popconfirm} from 'antd';
import  {useState} from 'react';
import {connect} from 'dva';
import style from './users.less'
import {add} from './service'
import UserModal from '../../component/UserModal/UserModal'const index = ({users,dispatch}) =>{const[modalVisible,setModalVisible] = useState(false);const[record,setRecord] = useState(undefined);const[userNameDisable,setUserNameDisable] = useState(false);const columns = [{title: '用户名',dataIndex: 'userName',key: 'userName',render: text => <a>{text}</a>,},{title: '年龄',dataIndex: 'age',key: 'age',},{title: '邮箱',dataIndex: 'email',key: 'email',},{title: '住址',dataIndex: 'address',key: 'address',},{title: '个性标签',key: 'tagList',dataIndex: 'tagList',render: tags => (<>{tags.map(tag => {let color = tag.length > 5 ? 'geekblue' : 'green';if (tag === 'loser') {color = 'volcano';}return (<Tag color={color} key={tag}>{tag.toUpperCase()}</Tag>);})}</>
),
},{title: '操作',key: 'action',render: (text, record) => (<Space size="middle"><a onClick={()=>{editHandler(record);}}>编辑</a><Popconfirmtitle="Are you sure delete this user?"onConfirm={() => {deleteHandler(record.userId);}}okText="Yes"cancelText="No"><a style={{color:'red'}}>删除</a></Popconfirm></Space>),},
];const editHandler = (record)=>{setModalVisible(true);setUserNameDisable(true);console.log(record);setRecord(record);};const addHandler = ()=>{setModalVisible(true);setUserNameDisable(false);};const deleteHandler = (userId:number)=>{dispatch({type: 'users/deleteById',payload: {userId,},});};const okClose = () =>{setModalVisible(false);};const cancelClose = () =>{setModalVisible(false);setRecord(undefined)};const onFinish = async values =>{if(record){values['userId'] = record.userId;dispatch({type:'users/edit',payload: values,});setModalVisible(false);}else {// dispatch({//   type:'users/add',//   payload: values,// });const response = await add(values);if(response.status){setModalVisible(false);}dispatch({type:'users/getRemote',});}};return (<div className={style["list-table"]}><Button style={{backgroundColor:'lightGreen'}} onClick={()=>{addHandler();}}>添加</Button><Table columns={columns}dataSource={users.data}pagination={{pageSize:8,}}rowKey="userName" /><UserModalvisible={modalVisible}okClose={okClose}cancelClose={cancelClose}record={record}onFinish = {onFinish}userNameDisable = {userNameDisable}/></div>)
};// const mapStateToProps = ({users})=>{//   console.log(users);
//   return {//     users,
//   }
// };const mapStateToProps = ({users})=>({users});export default connect(mapStateToProps)(index);

model.ts

import {Reducer,Effect,Subscription} from 'umi'
import {getRemote,edit,deleteById,add} from './service'interface UserModelType{namespace: 'users',state:{},reducers:{getList: Reducer},effects:{getRemote: Effectedit: Effectadd: EffectdeleteById: Effect},subscriptions:{setup: Subscription;}
}const userModel:UserModelType ={namespace: 'users',state:{},reducers:{getList(state,{payload}){return payload;},},effects: {*getRemote(action,{put,call}){const response = yield call(getRemote);console.log(response.data);const data = response.data;yield put({type: 'getList',payload: {data},});},*edit({payload: values},{put,call}){console.log('edit here',values);const response = yield call(edit,values);yield put({type: 'getRemote',});},*add({payload: values},{put,call}){console.log('add here',values);const response = yield call(add,values);yield put({type: 'getRemote',});},*deleteById({payload: userId},{put,call}){console.log('delete',userId);const response = yield call(deleteById,userId);yield put({type: 'getRemote',});},},subscriptions:{setup({dispatch,history}){return history.listen(({pathname})=>{if(pathname==='/users'){dispatch({type: 'getRemote'});}})}},
};export default userModel;

service.ts

import {request} from 'umi'
import {message} from 'antd'export const getRemote = async () =>{return request('/app/user/findList',{method:'get'}).then(function (response) {console.log(response);return response;}).catch(function (error) {console.log(error);});
};export const edit = async (values) =>{return request('/app/user/edit',{method:'post',data:values}).then(function (response) {if(response.status){message.success('编辑成功');}else {message.error(response.msg);}return response;}).catch(function (error) {message.error('编辑失败');console.log(error);});
};export const add = async (values) =>{return request('/app/user/add',{method:'post',data:values}).then(function (response) {if(response.status){message.success('添加成功');}else {message.error(response.msg);}return response;}).catch(function (error) {message.error('添加失败');console.log(error);});
};export const deleteById = async (userId) =>{return request('/app/user/delete',{method:'get',params:userId}).then(function (response) {message.success('删除成功');return response;}).catch(function (error) {message.error('删除失败');console.log(error);});
};

users.less

.list-table{margin: 50px auto 0;width: 80%;
}

二、后端

package com.example.readinglist.cms.controller;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.readinglist.cms.dto.ResponseDTO;
import com.example.readinglist.cms.entity.MyAppUser;
import com.example.readinglist.cms.service.MyAppUserService;
import com.example.readinglist.util.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.validation.Valid;
import java.util.Date;
import java.util.List;/*** <p>* 用户 前端控制器* </p>** @author cruder* @since 2021-04-13*/
@RestController
@RequestMapping("/app/user")
public class MyAppUserController {@Autowiredprivate MyAppUserService myAppUserService;@GetMapping("findList")public ResponseDTO findList(MyAppUser myAppUser){List<MyAppUser> myAppUsers = myAppUserService.list(new QueryWrapper<>(myAppUser).orderByDesc("create_time"));if(ListUtils.isNotEmpty(myAppUsers)){myAppUsers.forEach(user->{user.setTagList(user.getTags().split(","));});}return ResponseDTO.success(myAppUsers);}@PostMapping("edit")public ResponseDTO edit(@Valid @RequestBody MyAppUser myAppUser){myAppUser.setUpdateTime(new Date());myAppUserService.updateById(myAppUser);return ResponseDTO.success();}@PostMapping("add")public ResponseDTO add(@RequestBody MyAppUser myAppUser){MyAppUser one = myAppUserService.getOne(new QueryWrapper<MyAppUser>().eq("user_name", myAppUser.getUserName()));if(one!=null){return ResponseDTO.failed("此用户名此存在!");}myAppUser.setCreateTime(new Date());myAppUserService.save(myAppUser);return ResponseDTO.success();}@GetMapping("delete")public ResponseDTO delete(@RequestParam Integer userId){return ResponseDTO.success(myAppUserService.removeById(userId));}}

三、实现效果

四、参考
https://www.bilibili.com/video/BV1qz411z7s3?p=16

五、部署
npm run build 打包生成的文件夹dist上传到nginx的html文件夹下,将dist改为myapp

nginx 配置

server {listen       80;server_name  localhost;#charset koi8-r;#access_log  logs/host.access.log  main;location ~^/app/{proxy_pass   http://localhost:8080;}location ^~ /myapp/{root html;try_files $uri /myapp/index.html;index index.html index.htm;}}

配置好后,浏览器输入http://localhost/myapp/users既能访问,localhost是你的nginx的所在主机地址

基于umi写一个用户管理CRUD相关推荐

  1. 通过一个用户管理实例学习路由react-router-dom知识

    我们通过一个用户管理实例来学习react-router-dom 这个实例包括9个小组件 App.js 引入组件 Home.js 首页组件 User.js 用户管理组件 -  UserList.js 用 ...

  2. 【vite+vue3.0】基于vite写一个将md文件渲染为js文件的插件

    基于vite写一个将md文件渲染为js文件的插件 前言 尤大是这么描述 Vite 的: 「一个基于浏览器原生 ES imports 的开发服务器. 利用浏览器去解析 imports,在服务器端按需编译 ...

  3. python kivy显示图片_python基于Kivy写一个图形桌面时钟程序代码示例

    本篇文章小编给大家分享一下python基于Kivy写一个图形桌面时钟程序代码示例,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看. Kivy 是一个开源的 ...

  4. python时钟程序的设计总结_python基于Kivy写一个图形桌面时钟程序

    kivy 是一个开源的 python 第三方库,可以用来快速开发应用程序. 它有如下三个特点: 跨平台 kivy 编写的程序可在 linux,windows,os x,android,ios 和 ra ...

  5. 基于bootstrap实现简单用户管理功能

    基于bootstrap实现简单用户管理功能,包括增删改以及列表分页展示功能. 1.web.xml配置servlet映射: <servlet><servlet-name>User ...

  6. java写一个登录系统_用java写一个用户登陆界面

    一.课堂测试源代码及其结果截图 用java的swing写一个用户登录界面,采用网格布局.源代码如下: /** * */ package LiuLijia; import java.awt.CardLa ...

  7. 【Linux服务器开发系列】手写一个用户态网络协议栈,瞬间提升你网络功底丨netmap/dpdk的实现

    手写一个用户态网络协议栈,瞬间提升你网络功底 1. 网卡基础架构 2. netmap/dpdk的实现 3. 网络协议栈实战 [Linux服务器开发系列]手写一个用户态网络协议栈,瞬间提升你网络功底丨n ...

  8. python开发桌面时钟_python基于Kivy写一个图形桌面时钟程序

    Kivy 是一个开源的 Python 第三方库,可以用来快速开发应用程序. 它有如下三个特点: 跨平台 Kivy 编写的程序可在 Linux,Windows,OS X,Android,iOS 和 Ra ...

  9. 自动化测试(二)如何用python写一个用户登陆功能

    需求信息: 写一个判断登录的程序: 输入: username password 最大错误次数是3次,输入3次都没有登录成功,提示错误次数达到上限 需要判断输入是否为空,什么也不输入,输入一个空格.n个 ...

  10. 如何基于Python写一个TCP反向连接后门

    0x0 介绍 在Linux系统做未授权测试,我们须准备一个安全的渗透环境,通常第一件事就是安装虚拟机.且在攻击阶段中还需要对受害系统进行控制.常见的后门大多数是利用Metasploit生成,而目前反病 ...

最新文章

  1. java写exe程序实例,java实现可安装的exe程序实例详解
  2. 快手刘霁:AI基础能力决定每个公司AI的迭代和落地效率丨MEET2020
  3. java知识理论_JAVA理论知识 - OSC_rnoszD的个人空间 - OSCHINA - 中文开源技术交流社区...
  4. 不管马斯克怎么说,中国智能汽车激光雷达军备竞赛已经开始
  5. JSP中文乱码问题解决方案
  6. Excel绘制甘特图
  7. 在windows上linux命令行,如何在Windows中通过Cygwin来使用Linux命令行
  8. Object_id用法
  9. eclipse编译hadoop插件
  10. Day 02 第二天课时总结
  11. 中科院C语言应聘机试编程题6,中科院计算所保研笔试+机试+面试经验分享
  12. JS闭包—你不知道的JavaScript上卷读书笔记(二)
  13. 微软:“不好意思,我们还不够Cool,不能运行”
  14. Acrobat DC安装教程
  15. mysql报错1194_ERROR 1194 (HY000): Table 't1' is marked as crashed and should be repaired
  16. 如何使用微PE工具箱制作U盘PE
  17. 无WiFi 条件下如何使用Xshell 串口访问树莓派终端
  18. 工控系统 SCADA(监控和数据采集)系统简介
  19. 标贝科技|AI企业级应用榜单发布,百度、讯飞、标贝科技等50家产品上榜
  20. jQuery高亮显示

热门文章

  1. 2-14 DataTimePicker控件
  2. Castle IOC容器构建配置详解(二)
  3. 自定义类加载器与热部署
  4. Crawler 爬虫
  5. [JarvisOj][XMAN]lTell Me Something
  6. Asp.net core WebApi 使用Swagger生成帮助页实例
  7. 关于浏览器兼容的问题
  8. Maven与Ant使用reportNG代替testng
  9. ASP.NET基础教程-利用javascript将光标定位到文本框
  10. day09-线程与进程