• 手把手教你前后分离架构(五) SpringBoot连接数据库


    1、连接数据库

    管理系统离不开关系数据库的支持, 数据库采用mysql数据库。

    1.1、数据库创建

    MySQL在5.5.3之后增加了utf8mb4的字符集,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。utf8mb4是utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。 utf8mb4 是目前最大的一个字符编码,支持任意文字。

    utf8mb4对应的排序字符集有utf8mb4_unicode_ci、utf8mb4_general_ci.
    utf8mb4_unicode_ci是基于标准的Unicode来排序和比较,能够在各种语言之间精确排序.在特殊情况下,Unicode排序规则为了能够处理特殊字符的情况,实现了略微复杂的排序算法。
    utf8mb4_general_ci没有实现Unicode排序规则,在遇到某些特殊语言或者字符集,排序结果可能不一致。
    utf8mb4_unicode_ci 校对速度快,但准确度稍差。utf8_unicode_ci准确度高,但校对速度稍慢,两者都不区分大小写。通常情况下,新建数据库时一般选用 utf8mb4_general_ci 就可以了

    1. //创建数据
    2. CREATE DATABASE mir DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    3. //创建用户并授权
    4. CREATE USER 'mir'@'%' IDENTIFIED BY '123456';
    5. GRANT ALL PRIVILEGES ON mir.* TO 'mir'@'%';
    6. FLUSH PRIVILEGES;

    MySQL存储引擎

    Innodb引擎:Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。

    MyIASM引擎(原本Mysql的默认引擎):不提供事务的支持,也不支持行级锁和外键。

    1.2、整合Mybaties-Plus

    有很多持久层框架帮助我们更方便的操作数据库。常用的持久层框架有MyBatis 、hibernate等等。我们采用Mybatis-Plus作为系统持久层框架,Mybatis-Plus是一个Mybatis的增强工具,只是在Mybatis的基础上做了增强却不做改变,MyBatis-Plus支持所有Mybatis原生的特性,所以引入Mybatis-Plus不会对现有的Mybatis构架产生任何影响。Mybatis-Plus有依赖少、损耗小、预防Sql注入等诸多优点。

    官网地址:安装 | MyBatis-Plus

    1.2.2、依赖安装

    1. <dependency>
    2. <groupId>com.baomidou</groupId>
    3. <artifactId>mybatis-plus-boot-starter</artifactId>
    4. <version>3.4.1</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>mysql</groupId>
    8. <artifactId>mysql-connector-java</artifactId>
    9. <version>8.0.25</version>
    10. </dependency>
    11. <dependency>
    12. <groupId>com.alibaba</groupId>
    13. <artifactId>druid-spring-boot-starter</artifactId>
    14. <version>1.1.10</version>
    15. </dependency>

    1.2.2、添加配置

    1. spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    2. spring.datasource.driver-class-name= com.mysql.cj.jdbc.Driver
    3. spring.datasource.url= jdbc:mysql://localhost:3306/mir
    4. spring.datasource.username=mir
    5. spring.datasource.password=123456

    1.2.3、添加config配置

    1. @Configuration
    2. @MapperScan({"com.example.*.mapper"})
    3. public class MyBatisPlusConfig {
    4. }

    如果配置全局扫描可以在Mapper接口添加   @Mapper 注解。

    1.2.4、代码生成器

    手动参照数据库字段编写对象实体等字段,很麻烦而且容易出错,MyBatis-Plus 代码生成器可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

    https://baomidou.com/pages/779a6e/#快速入门  参照官网

     mybatis-plus-generator 3.5.1 及其以上版本可使用新版本代码生成器。

    添加依赖

    1. <dependency>
    2. <groupId>com.baomidou</groupId>
    3. <artifactId>mybatis-plus-generator</artifactId>
    4. <version>3.5.2</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>org.freemarker</groupId>
    8. <artifactId>freemarker</artifactId>
    9. <version>2.3.31</version>
    10. </dependency>

    样例

    1. public static void main(String[] args) {
    2. String url = "jdbc:mysql://localhost:3306/mir";
    3. String username = "mir";
    4. String password = "123456";
    5. FastAutoGenerator.create(url, username, password)
    6. .globalConfig(builder -> {
    7. builder.author("dehuisun") // 设置作者
    8. .enableSwagger() // 开启 swagger 模式
    9. .fileOverride() // 覆盖已生成文件
    10. .outputDir("D://generator"); // 指定输出目录
    11. })
    12. .packageConfig(builder -> {
    13. builder.parent("com.xgg") // 设置父包名
    14. .moduleName("sys") // 设置父包模块名
    15. .pathInfo(Collections.singletonMap(OutputFile.xml, "D://generator")); // 设置mapperXml生成路径
    16. })
    17. .strategyConfig(builder -> {
    18. builder.addInclude("sys_user") // 设置需要生成的表名
    19. .addTablePrefix("t_", "c_"); // 设置过滤表前缀
    20. })
    21. .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
    22. .execute();
    23. }

    1.3、数据持久化规范

    为了更好研发建议迭代系统,所以我们需要制定一些研发规范来帮助我们快速迭代。

    1.3.1、数据库建表规范

    为数据库表添加一些公共字段,比如deleted(逻辑删除标识)、create_time、update_time、create_by、update_by等等来实现数据添加变更记录、逻辑删除、乐观锁等业务需求。帮助我们实现数据恢复及数据修改回溯。

    1.3.2、自动填充公共字段

    业务表中有create_time、update_time、create_by、update_by这四个字段,create_time、update_time要自动填充为当前时间,create_by、update_by自动填充为当前登录的用户ID。

    配置类

    1. @Bean
    2. public OptimisticLockerInterceptor mybatisPlusInterceptor() {
    3. return new OptimisticLockerInterceptor();
    4. }
    5. @Bean
    6. public MetaObjectHandler metaObjectHandler() {
    7. return new MetaObjectHandler() {
    8. @Override
    9. public void insertFill(MetaObject metaObject) {
    10. SysUser user = getUserId(metaObject);
    11. if (!Objects.isNull(user)) {
    12. this.strictInsertFill(metaObject, "createBy", Long.class, user.getId());
    13. }
    14. this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
    15. }
    16. @Override
    17. public void updateFill(MetaObject metaObject) {
    18. SysUser user = getUserId(metaObject);
    19. if (!Objects.isNull(user)) {
    20. this.strictUpdateFill(metaObject, "updateBy", Long.class, user.getId());
    21. }
    22. this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    23. }
    24. private SysUser getUserId(MetaObject metaObject) {
    25. //自己认证框架获取登录用户的方法
    26. }
    27. };

    1.3.3、逻辑删除

    添加配置文件

    1. mybatis-plus.global-config.db-config.logic-delete-field=deleted
    2. mybatis-plus.global-config.db-config.logic-delete-value=1
    3. mybatis-plus.global-config.db-config.logic-not-delete-value=0

    实体注解

    1. @TableLogic
    2. private Integer deleted;

    1.3.4抽象公共实体类

    1. @Getter
    2. public class BaseEntity {
    3. @TableLogic
    4. private Integer deleted;
    5. @TableField(fill = FieldFill.INSERT)
    6. private Long createUserId;
    7. @TableField(fill = FieldFill.UPDATE)
    8. private Long updateUserId;
    9. @TableField(fill = FieldFill.INSERT)
    10. private LocalDateTime createTime;
    11. @TableField(fill = FieldFill.UPDATE)
    12. private LocalDateTime updateTime;
    13. @TableLogic
    14. private Integer deleted;
    15. }

    公共实体类只添加getter方法,防止手动set赋值字段。

    继承公共实体:

    还有乐观锁等特性,可以后续根据需求来实现。

    2、用户管理功能实现

    2.1、后端实现

    2.1.1 分层规范

    系统参照阿里分层规范

    • Web 层:controller层主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。

    • Service 层:相对具体的业务逻辑服务层。

    • Manager 层:通用业务处理层,它有如下特征:

    1) 对第三方平台封装的层,预处理返回结果及转化异常信息,适配上层接口。

    2) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。

    3) 与 DAO 层交互,对多个 DAO 的组合复用。

    • DAO 层:数据访问Mapper层,与底层 MySQL、Oracle、Hbase、OB 等进行数据交互。

    2.1.2、创建用户表

    1. CREATE TABLE `sys_user` (
    2. `id` BIGINT NOT NULL,
    3. `account` VARCHAR(50) NOT NULL COMMENT '账号',
    4. `username` VARCHAR(240) NOT NULL COMMENT '用户名',
    5. `password` VARCHAR(100) NOT NULL COMMENT '密码',
    6. `salt` VARCHAR(64) DEFAULT NULL COMMENT '盐',
    7. `email` VARCHAR(64) DEFAULT NULL COMMENT '邮箱',
    8. `mobile` VARCHAR(64) DEFAULT NULL COMMENT '手机号',
    9. `status` SMALLINT(6) DEFAULT '0' COMMENT '状态(0:正常1:停用2:锁定)',
    10. `err_num` TINYINT DEFAULT NULL COMMENT '登录错误次数',
    11. `lock_time` DATETIME DEFAULT NULL COMMENT '锁定时间',
    12. `create_by` BIGINT UNSIGNED DEFAULT NULL COMMENT '创建者ID',
    13. `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
    14. `update_by` BIGINT UNSIGNED DEFAULT NULL COMMENT '修改人ID',
    15. `update_time` DATETIME DEFAULT NULL COMMENT '修改时间',
    16. `deleted` TINYINT DEFAULT '0' COMMENT '是否被删除(0:未删除,1:已删除)',
    17. PRIMARY KEY (`id`)
    18. ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='用户管理'

    2.1.3、代码生成

    生成的代码拷贝至项目

    2.1.4、接口实现

    1. @RestController
    2. @Api(tags = "用户管理服务")
    3. @RequestMapping("/sys/user")
    4. public class UserController {
    5. @Resource
    6. private IUserService userService;
    7. @GetMapping("/page")
    8. @ApiOperation(value = "用户列表分页查询")
    9. public Result<Page<UserVO>> getPageList(@Valid UserPageParam userParam) {
    10. Page<User> page = new Page(userParam.getCurrent(), userParam.getSize());
    11. userService.pageList(page, userParam.getUsername());
    12. Page<UserVO> pageResult = CollectionUtils.page(page, UserVO.class);
    13. return Result.ok().info(pageResult);
    14. }
    15. @ApiOperation("用户查询")
    16. @GetMapping("/{id}")
    17. @ApiImplicitParam(name = "id", value = "用户ID", required = true, paramType = "path", dataType = "Long")
    18. public Result<UserVO> getInfo(@PathVariable("id") Long id) {
    19. User user = userService.getById(id);
    20. UserVO userVO = new UserVO();
    21. if(user!=null) {
    22. BeanUtils.copyProperties(user, userVO);
    23. }
    24. return Result.ok().info(userVO);
    25. }
    26. @ApiOperation("用户删除")
    27. @DeleteMapping("/{id}")
    28. @ApiImplicitParam(name = "id", value = "用户ID", required = true, paramType = "path", dataType = "Long")
    29. public Result delete(@PathVariable Long id) throws Exception {
    30. // User user = (User) SecurityUtils.getSubject().getPrincipal();
    31. // if (sysUser.getId().equals(id)) {
    32. // return Result.error().message("不能删除当前登录用户");
    33. // }
    34. userService.removeById(id);
    35. return Result.ok();
    36. }
    37. @ApiOperation("用户新增")
    38. @PostMapping("")
    39. public Result save(@Validated(AddGroup.class) @RequestBody UserParam userParam) {
    40. User sysUser = new User();
    41. sysUser.setAccount(userParam.getAccount());
    42. sysUser.setUsername(userParam.getUsername());
    43. List<User> list = userService.list(new QueryWrapper<>(sysUser));
    44. if (list!=null&&list.size() != 0) {
    45. return Result.error().message("该账号已存在!");
    46. }
    47. BeanUtils.copyProperties(userParam, sysUser);
    48. sysUser.setId(null);
    49. sysUser.setPassword(Constant.PASSWORD);
    50. userService.save(sysUser);
    51. return Result.ok();
    52. }
    53. @ApiOperation("用户更新")
    54. @PutMapping("")
    55. public Result update(@Validated(UpdateGroup.class) @RequestBody UserParam userParam) {
    56. User sysUser = new User();
    57. sysUser.setAccount(userParam.getAccount());
    58. sysUser.setUsername(userParam.getUsername());
    59. List<User> list = userService.list(new QueryWrapper<>(sysUser));
    60. if (list!=null&&list.size() != 0) {
    61. return Result.error().message("该账号已存在!");
    62. }
    63. sysUser = userService.getById(userParam.getId());
    64. BeanUtils.copyProperties(userParam, sysUser);
    65. userService.updateById(sysUser);
    66. return Result.ok();
    67. }
    68. }

    接口实现参数校验(分组校验等多种方式)、统一返回、每层实体参数规划。用户实体继承公共参数。

    2.1.5 解决精度丢失问题

    1. @Configuration
    2. @EnableWebMvc
    3. public class JacksonConfig implements WebMvcConfigurer {
    4. @Override
    5. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    6. MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
    7. ObjectMapper objectMapper = new ObjectMapper();
    8. /**
    9. * 序列换成json时,将所有的long变成string
    10. * 因为js中得数字类型不能包含所有的java long值
    11. */
    12. SimpleModule simpleModule = new SimpleModule();
    13. simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
    14. simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
    15. objectMapper.registerModule(simpleModule);
    16. jackson2HttpMessageConverter.setObjectMapper(objectMapper);
    17. converters.add(jackson2HttpMessageConverter);
    18. }
    19. }

    2.1.6参数序列化问题

    @JsonIgnoreProperties(ignoreUnknown = true)

    2.2、前端实现

    2.2.1实现列表和详情页

    1. <template>
    2. <div>
    3. <el-form :model="tableForm" ref="tableForm">
    4. <el-row :gutter="20" >
    5. <el-col :xs="24" :sm="6" >
    6. <el-form-item prop="classCode">
    7. <el-input v-model="tableForm.name" placeholder="姓名" maxlength="20" clearable></el-input>
    8. </el-form-item>
    9. </el-col>
    10. <el-col :xs="{span:24,offset:0}" :sm="{span:18,offset:0}">
    11. <el-form-item style="float: right">
    12. <el-button type="primary" @click="getTableData()" icon="el-icon-search">查询</el-button>
    13. <el-button type="default" @click="resetForm('tableForm')" plain icon="el-icon-refresh-left">重置</el-button>
    14. </el-form-item>
    15. </el-col>
    16. </el-row>
    17. </el-form>
    18. <el-divider></el-divider>
    19. <el-row style="padding-bottom: 5px;">
    20. <el-col :span="24">
    21. <el-button type="primary" icon="el-icon-plus" @click="doEdit()">新增</el-button>
    22. <!-- <el-button type="primary" icon="el-icon-plus" @click="doDrawer()">抽屉</el-button>-->
    23. </el-col>
    24. </el-row>
    25. <el-table
    26. header-cell-class-name="custom_table_header"
    27. :data="tableData.records"
    28. border
    29. v-loading="tableDataLoading"
    30. style="width: 100%">
    31. <el-table-column
    32. type="index"
    33. label="#"
    34. align="center"
    35. fixed="left"
    36. width="50">
    37. </el-table-column>
    38. <el-table-column prop="account" header-align="center" align="center" label="登录账号"></el-table-column>
    39. <el-table-column prop="username" header-align="center" align="center" label="用户名"></el-table-column>
    40. <el-table-column prop="mobile" header-align="center" align="center" label="手机号"></el-table-column>
    41. <el-table-column prop="email" header-align="center" align="center" label="邮箱"></el-table-column>
    42. <el-table-column prop="status" header-align="center" align="center" label="状态">
    43. <template slot-scope="scope">
    44. <el-tag v-if="scope.row.status === 0" >正常</el-tag>
    45. <el-tag v-else type="danger">禁用</el-tag>
    46. </template>
    47. </el-table-column>
    48. <el-table-column prop="createTime" header-align="center" align="center" width="200"
    49. label="创建时间" :formatter="formatterDateTime"></el-table-column>
    50. <el-table-column fixed="right" header-align="center" align="center" width="120" label="操作">
    51. <template slot-scope="scope">
    52. <el-button type="text" @click="doEdit(scope.row.id)">编辑</el-button>
    53. <el-button type="text" @click="doDel(scope.row.id)">删除</el-button>
    54. </template>
    55. </el-table-column>
    56. </el-table>
    57. <el-pagination
    58. @size-change="sizeChangeHandle"
    59. @current-change="currentChangeHandle"
    60. :current-page="tableData.current"
    61. :page-sizes="[10, 20, 50, 100]"
    62. :page-size="tableData.size"
    63. :total="tableData.total"
    64. :layout="pageLayout">
    65. </el-pagination>
    66. <add-dialog ref="addDialog" @refreshDataList="getTableData"></add-dialog>
    67. <add-drawer ref="addDrawer" @refreshDataList="getTableData"></add-drawer>
    68. </div>
    69. </template>
    70. <script>
    71. import AddDialog from './user-addDialog'
    72. import AddDrawer from './user-addDrawer'
    73. import axios from 'axios'
    74. import {formartDateTime} from '@/utils'
    75. export default {
    76. data() {
    77. return {
    78. tableForm: {
    79. name: '',
    80. province: ''
    81. },
    82. tableData: {
    83. records: [],
    84. total: 0,
    85. size: 10,
    86. current: 1,
    87. pages: 1
    88. },
    89. tableDataLoading: false,
    90. tableDataSelections: [],
    91. }
    92. },
    93. components: {
    94. AddDialog,
    95. AddDrawer
    96. },
    97. methods: {
    98. // 获取数据列表
    99. getTableData() {
    100. this.tableForm.current = this.tableData.current;
    101. this.tableForm.size = this.tableData.size;
    102. this.tableDataLoading = true;
    103. axios.get('http://127.0.0.1:8888/sys/user/page',{
    104. params: this.tableForm
    105. }).then(({data}) => {
    106. if (data.success) {
    107. this.tableData = data.info;
    108. this.tableDataLoading = false
    109. } else {
    110. this.$message.error(data.message)
    111. }
    112. }).catch(() => {
    113. this.$message.error(this.tips.error);
    114. }
    115. )
    116. },
    117. // 每页数
    118. sizeChangeHandle(val) {
    119. this.tableData.size = val;
    120. this.getTableData()
    121. },
    122. // 当前页
    123. currentChangeHandle(val) {
    124. this.tableData.current = val;
    125. this.getTableData()
    126. },
    127. handleClick(row) {
    128. console.log(row);
    129. },
    130. onSubmit() {
    131. console.log('submit!');
    132. },
    133. doEdit(id){
    134. this.$nextTick(()=>{
    135. this.$refs.addDialog.init(id);
    136. })
    137. },
    138. // 删除
    139. doDel(id) {
    140. this.$confirm(this.tips.isSure, this.tips.tips, {}).then(() => {
    141. //防止表单重复提交
    142. this.$MessageBox.showLoading();
    143. axios.delete(`http://127.0.0.1:8888/sys/user/${id}`
    144. ).then(({data}) => {
    145. this.$MessageBox.hideLoading();
    146. this.getTableData();
    147. if (data.success) {
    148. this.$message.success(data.message)
    149. } else {
    150. this.$message.error(data.message)
    151. }
    152. }).catch(() => {
    153. this.$MessageBox.hideLoading()
    154. this.$message.error(this.tips.error);
    155. })
    156. })
    157. },
    158. doDrawer(id){
    159. this.$nextTick(()=>{
    160. this.$refs.addDrawer.init(id);
    161. })
    162. },
    163. //时间格式化
    164. formatterDateTime: function (row, column, cellValue, index) {
    165. return formartDateTime(cellValue)
    166. },
    167. },
    168. activated() {
    169. this.getTableData()
    170. },
    171. computed: {
    172. pageLayout() {
    173. if (this.$store.state.common.clientType === 'phone') return 'total, sizes, prev, pager, next'
    174. return 'total, sizes, prev, pager, next, jumper'
    175. }
    176. },
    177. }
    178. </script>
    179. <style scoped>
    180. </style>
    1. <template>
    2. <div>
    3. <el-dialog title="" class="custom_dialog"
    4. :close-on-click-modal = "false"
    5. :visible.sync="visible">
    6. <div slot="title" class="dialog-title">
    7. <i class="el-icon-edit-outline"></i>
    8. <span class="title-text">用户维护</span>
    9. </div>
    10. <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="doSubmit()" :label-width="formLabelWidth">
    11. <el-form-item label="账号" prop="account">
    12. <el-input v-model="dataForm.account" autocomplete="off" ></el-input>
    13. </el-form-item>
    14. <el-form-item label="用户名" prop="username">
    15. <el-input v-model="dataForm.username" autocomplete="off"></el-input>
    16. </el-form-item>
    17. <el-form-item label="手机号" prop="mobile">
    18. <el-input v-model="dataForm.mobile" autocomplete="off"></el-input>
    19. </el-form-item>
    20. <el-form-item label="邮箱" prop="email">
    21. <el-input v-model="dataForm.email" autocomplete="off"></el-input>
    22. </el-form-item>
    23. </el-form>
    24. <div slot="footer" class="dialog-footer">
    25. <el-button @click="visible = false"><i class="el-icon-close"></i>取 消</el-button>
    26. <el-button type="primary" @click="doSubmit()"><i class="el-icon-check"></i>确 定</el-button>
    27. </div>
    28. </el-dialog>
    29. </div>
    30. </template>
    31. <script>
    32. import axios from "axios";
    33. import {isEmail, isMobile} from '@/utils/validate'
    34. export default {
    35. data() {
    36. var validateEmail = (rule, value, callback) => {
    37. if (value && !isEmail(value)) {
    38. callback(new Error('邮箱格式错误'))
    39. } else {
    40. callback()
    41. }
    42. }
    43. var validateMobile = (rule, value, callback) => {
    44. if (value && !isMobile(value)) {
    45. callback(new Error('手机号格式错误'))
    46. } else {
    47. callback()
    48. }
    49. }
    50. return {
    51. visible: false,
    52. dataForm: {
    53. id: '',
    54. account: '',
    55. username: '',
    56. email: '',
    57. mobile: '',
    58. status: ''
    59. },
    60. formLabelWidth: '120px',
    61. dataRule: {
    62. account: [
    63. {required: true, message: '账号不能为空', trigger: 'blur'},
    64. { min: 3, max: 5, message: '账号长度在 3 到 10 个字符', trigger: 'blur' }
    65. ],
    66. username: [
    67. {required: true, message: '用户名不能为空', trigger: 'blur'},
    68. { min: 2, max: 5, message: '用户名长度在 2 到 5 个字符', trigger: 'blur' }
    69. ],
    70. email: [
    71. { required: true, message: '邮箱不能为空', trigger: 'blur' },
    72. {validator: validateEmail, trigger: 'blur'}
    73. ],
    74. mobile: [
    75. { required: true, message: '手机号不能为空', trigger: 'blur' },
    76. {validator: validateMobile, trigger: 'blur'}
    77. ]
    78. }
    79. };
    80. },
    81. methods: {
    82. init(id){
    83. this.visible = true;
    84. this.dataForm.id = id || ''
    85. this.$nextTick(() => {
    86. this.$refs['dataForm'].resetFields()
    87. })
    88. if (this.dataForm.id) {
    89. axios.get(`http://127.0.0.1:8888/sys/user/${this.dataForm.id}`,
    90. ).then(({data}) => {
    91. if (data.success) {
    92. this.dataForm = data.info;
    93. }
    94. })
    95. }
    96. },
    97. doSubmit(){
    98. this.$refs['dataForm'].validate((valid) => {
    99. if (valid) {
    100. //防止表单重复提交
    101. this.$MessageBox.showLoading()
    102. if (this.dataForm.id) {
    103. axios.put('http://127.0.0.1:8888/sys/user', this.dataForm
    104. ).then(({data}) => {
    105. this.$MessageBox.hideLoading()
    106. if (data.success) {
    107. this.visible = false
    108. this.$emit('refreshDataList')
    109. this.$message.success(data.message)
    110. } else {
    111. this.$message.error(data.message)
    112. }
    113. }).catch(({data}) => {
    114. this.$MessageBox.hideLoading()
    115. this.$message.error(this.tips.error);
    116. })
    117. }else{
    118. axios.post('http://127.0.0.1:8888/sys/user', this.dataForm
    119. ).then(({data}) => {
    120. this.$MessageBox.hideLoading()
    121. this.visible = false
    122. this.$emit('refreshDataList')
    123. if (data.success) {
    124. this.$message.success(data.message)
    125. } else {
    126. this.$message.error(data.message)
    127. }
    128. }).catch(({data}) => {
    129. this.$MessageBox.hideLoading()
    130. this.$message.error(this.tips.error);
    131. })
    132. }
    133. }
    134. })
    135. }
    136. },
    137. };
    138. </script>
    139. <style scoped>
    140. </style>

    2.2.2添加路由

    {path: '/user', name: 'user', component: _import('sys/user-list'),meta: {title:'用户管理',isTab:true}},

    2.2.3、添加菜单

    <el-menu-item index="1-4" @click="$router.push({ name: 'user' })">用户管理</el-menu-item>

    2.2.4、添加常量类

    tips.js

    1. const error = "系统异常,请稍后重试"
    2. export default{
    3. error
    4. }

    Main.js

    1. import tips from "@/constants/tips.js"
    2. Vue.prototype.tips = tips

    2.2.5、测试

     

    关注公众号”小猿架构“,发送 "前后分离架构" ,下载课程视频+课程源码+课件。

  • 相关阅读:
    LeetCode 刷题系列 -- 47. 全排列 II
    【Try Hack Me】Enumerating Active Directory
    Docker 问题记录
    《Qt开发》基于QWT的柱形图绘制
    java虚拟机详解篇五(类的加载器)
    全量、增量数据在HBase迁移的多种技巧实践
    使用DIV+CSS进行网页布局设计【HTML节日介绍网站——二十四节气】
    关于AWS负载均衡器的使用
    Android 启动流程及 init 进程解析
    windows下使用php-ffmpeg获取视频第一帧的图片
  • 原文地址:https://blog.csdn.net/sundehui01/article/details/125404474