企业OA办公系统开发笔记:2、MyBatis-Plus

文章目录

  • 企业办公系统:2、MyBatis-Plus
    • 一、MyBatis-Plus
      • 1、简介
      • 2、主要特点
      • 3、依赖
    • 二、MyBatis-Plus入门
      • 1、配置文件
      • 2、启动类
      • 3、实体类
      • 4、添加Mapper类
      • 5、测试Mapper接口
      • 6、CRUD测试
        • 6.1、insert添加
          • 6.1.1、示例
          • 6.1.2、主键策略
        • 6.2、更新
        • 6.3、删除
          • 6.3.1、根据id删除
          • 6.3.2、批量删除
        • 6.4、MyBatis-Plus条件构造器
      • 6、MyBatis-Plus封装service层
        • 6.1、添加service接口
        • 6.2、添加service接口实现
        • 6.3、测试Service接口
    • 三、角色管理
      • 1、测试controller层
        • 1.1、添加Controller
        • 1.2、测试Controller接口
      • 2、定义统一返回结果对象
        • 2.1、定义统一返回结果对象
        • 2.2、改造controller方法
        • 2.3、测试接口
      • 3、knife4j
        • 3.1、Swagger介绍
        • 3.2、集成knife4j
          • 3.2.1 添加依赖
          • 3.2.2 添加knife4j配置类
          • 3.2.3 Controller层添加注解
          • 3.2.4、测试
      • 4、分页查询
        • 4.1、配置分页插件
        • 4.2、分页controller
      • 5、其他controller方法
      • 6、统一异常处理
        • 6.1、制造异常
        • 6.2、全局异常处理
          • 6.2.1、创建统一异常处理器
          • 6.2.1、测试
        • 6.3、处理特定异常
          • 6.3.1、添加异常处理方法
          • 6.3.2、测试
        • 6.4、处理自定义异常
          • 6.4.1、创建自定义异常类
          • 6.4.2、业务中需要位置抛出
          • 6.4.3、添加异常处理方法

企业办公系统:2、MyBatis-Plus

一、MyBatis-Plus

官网:https://baomidou.com/

1、简介

MyBatis-Plus(简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

2、主要特点

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库

3、依赖

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version>
</dependency>

二、MyBatis-Plus入门

前面介绍了MyBatis-Plus,当前就以角色管理为例讲解MyBatis-Plus的使用

1、配置文件

配置 MySQL 数据库的相关配置及Mybatis-Plus日志

application.yml

spring:application:name: service-oaprofiles:active: dev

application-dev.yml

server:port: 8800
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 查看日志
spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/survey-oa?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8username: rootpassword: 123456

2、启动类

在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:

package com.atsurvey;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;/*** @Author tigerhhzz* @Date 2024 05 01 13 01**/@SpringBootApplication
//@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
@ComponentScan("com.atsurvey")
//@MapperScan("com.atsurvey.*.mapper")
@MapperScan("com.atsurvey.auth.mapper")
public class ServiceAuthApplication {public static void main(String[] args) {SpringApplication.run(ServiceAuthApplication.class, args);}}

3、实体类

已引入,实体类说明:

实体类注解详细文档:https://baomidou.com/pages/223848/

@TableName:表名注解,标识实体类对应的表

@TableId:主键注解,type = IdType.AUTO(数据库 ID 自增)

@TableField:字段注解(非主键)

@TableLogic:逻辑删除

package com.atsurvey.model.system;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.atsurvey.model.base.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "角色")
@TableName("sys_role")
public class SysRole extends BaseEntity {private static final long serialVersionUID = 1L;//@NotBlank(message = "角色名称不能为空")@ApiModelProperty(value = "角色名称")@TableField("role_name")private String roleName;@ApiModelProperty(value = "角色编码")@TableField("role_code")private String roleCode;@ApiModelProperty(value = "描述")@TableField("description")private String description;}

4、添加Mapper类

package com.atsurvey.auth.mapper;import com.atsurvey.model.system.SysRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;/*** @Author tigerhhzz* @Date 2024 05 01 13 04**/
@Repository
public interface SysRoleMapper extends BaseMapper<SysRole> {}

com.baomidou.mybatisplus.core.mapper.BaseMapper这是Mybatis-Plus提供的默认Mapper接口。

package com.baomidou.mybatisplus.core.mapper;import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;public interface BaseMapper<T> extends Mapper<T> {int insert(T entity);int deleteById(Serializable id);int deleteByMap(@Param("cm") Map<String, Object> columnMap);int delete(@Param("ew") Wrapper<T> queryWrapper);int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);int updateById(@Param("et") T entity);int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);T selectById(Serializable id);List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);T selectOne(@Param("ew") Wrapper<T> queryWrapper);Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}

5、测试Mapper接口

package com.atsurvey.auth;import com.atsurvey.auth.mapper.SysRoleMapper;
import com.atsurvey.model.system.SysRole;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.Arrays;
import java.util.List;/*** @Author tigerhhzz* @Date 2024 05 01 16 50**/
@SpringBootTest
public class TestMpDemo1 {//注入@Autowiredprivate SysRoleMapper sysRoleMapper;//查询所有记录@Testpublic void getAll() {List<SysRole> list = sysRoleMapper.selectList(null);System.out.println(list);}//添加操作@Testpublic void add() {SysRole sysRole = new SysRole();sysRole.setRoleName("角色管理员2");sysRole.setRoleCode("role2");sysRole.setDescription("角色管理员2");int rows = sysRoleMapper.insert(sysRole);System.out.println(rows);System.out.println(sysRole.getId());}//修改操作@Testpublic void update() {//根据id查询SysRole role = sysRoleMapper.selectById(10);//设置修改值role.setRoleName("atsurvey角色管理员");//调用方法实现最终修改int rows = sysRoleMapper.updateById(role);System.out.println(rows);}//删除操作@Testpublic void deleteId() {int rows = sysRoleMapper.deleteById(10);}//批量删除@Testpublic void testDeleteBatchIds() {int result = sysRoleMapper.deleteBatchIds(Arrays.asList(1, 2));System.out.println(result);}//条件查询@Testpublic void testQuery1() {//创建QueryWrapper对象,调用方法封装条件QueryWrapper<SysRole> wrapper = new QueryWrapper<>();wrapper.eq("role_name","总经理");//调用mp方法实现查询操作List<SysRole> list = sysRoleMapper.selectList(wrapper);System.out.println(list);}@Testpublic void testQuery2() {//LambdaQueryWrapper,调用方法封装条件LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();wrapper.eq(SysRole::getRoleName,"总经理");//调用mp方法实现查询操作List<SysRole> list = sysRoleMapper.selectList(wrapper);System.out.println(list);}
}

注意:

IDEA在sysRoleMapper处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确的执行。

为了避免报错,可以在 mapper 层 的接口上添加 @Repository 或直接使用 @Resource 代替 @Autowired。

控制台输出:

在这里插入图片描述

通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!

6、CRUD测试

6.1、insert添加
6.1.1、示例
    //添加操作@Testpublic void add() {SysRole sysRole = new SysRole();sysRole.setRoleName("角色管理员2");sysRole.setRoleCode("role2");sysRole.setDescription("角色管理员2");int rows = sysRoleMapper.insert(sysRole);System.out.println(rows);System.out.println(sysRole.getId());}
6.1.2、主键策略

1、ID_WORKER

MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID

2、自增策略

  • 要想主键自增需要配置如下主键策略

    • 需要在创建数据表的时候设置主键自增
    • 实体字段中配置 @TableId(type = IdType.AUTO)
@TableId(type = IdType.AUTO)
private Long id;

其它主键策略:分析 IdType 源码可知

public enum IdType {/*** 数据库ID自增*/AUTO(0),/*** 该类型为未设置主键类型*/NONE(1),/*** 用户输入ID* 该类型可以通过自己注册自动填充插件进行填充*/    INPUT(2),/*** 全局唯一ID*/    ASSIGN_ID(3),/*** 全局唯一ID (UUID)*/ASSIGN_UUID(4),/** @deprecated */@DeprecatedID_WORKER(3),/** @deprecated */@DeprecatedID_WORKER_STR(3),/** @deprecated */@DeprecatedUUID(4);private final int key;private IdType(int key) {this.key = key;}public int getKey() {return this.key;}
}
6.2、更新
@Test
public void testUpdateById(){SysRole sysRole = new SysRole();sysRole.setId(1L);sysRole.setRoleName("角色管理员1");int result = sysRoleMapper.updateById(sysRole);System.out.println(result);}
6.3、删除
6.3.1、根据id删除
/*** application-dev.yml 加入配置* 此为默认值,如果你的默认值和mp默认的一样,则不需要该配置* mybatis-plus:*   global-config:*     db-config:*       logic-delete-value: 1*       logic-not-delete-value: 0*/
@Test
public void testDeleteById(){int result = sysRoleMapper.deleteById(2L);System.out.println(result);
}
6.3.2、批量删除
@Test
public void testDeleteBatchIds() {int result = sysRoleMapper.deleteBatchIds(Arrays.asList(1, 1));System.out.println(result);
}
6.4、MyBatis-Plus条件构造器

在这里插入图片描述

Wrapper : 条件构造抽象类,最顶端父类

AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件

​ QueryWrapper : Entity 对象封装操作类,不是用lambda语法

​ UpdateWrapper : Update 条件封装,用于Entity对象更新操作

AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。

​ LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper

​ LambdaUpdateWrapper : Lambda 更新封装Wrapper

注意:以下条件构造器的方法入参中的 column 均表示数据库字段

@Test
public void testSelect1() {QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();queryWrapper.eq("role_code", "role");List<SysRole> users = sysRoleMapper.selectList(queryWrapper);System.out.println(users);
}@Test
public void testSelect2() {LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(SysRole::getRoleCode, "role");List<SysRole> users = sysRoleMapper.selectList(queryWrapper);System.out.println(users);
}

其他条件构造可自行测试

6、MyBatis-Plus封装service层

6.1、添加service接口
package com.atsurvey.auth.service;import com.atsurvey.model.system.SysRole;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.stereotype.Service;import java.util.Map;@Service
public interface SysRoleService extends IService<SysRole> {}

com.baomidou.mybatisplus.extension.service.IService这是Mybatis-Plus提供的默认Service接口。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.baomidou.mybatisplus.extension.service;import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.kotlin.KtQueryChainWrapper;
import com.baomidou.mybatisplus.extension.kotlin.KtUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;public interface IService<T> {int DEFAULT_BATCH_SIZE = 1000;default boolean save(T entity) {return SqlHelper.retBool(this.getBaseMapper().insert(entity));}@Transactional(rollbackFor = {Exception.class})default boolean saveBatch(Collection<T> entityList) {return this.saveBatch(entityList, 1000);}boolean saveBatch(Collection<T> entityList, int batchSize);@Transactional(rollbackFor = {Exception.class})default boolean saveOrUpdateBatch(Collection<T> entityList) {return this.saveOrUpdateBatch(entityList, 1000);}boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);default boolean removeById(Serializable id) {return SqlHelper.retBool(this.getBaseMapper().deleteById(id));}default boolean removeByMap(Map<String, Object> columnMap) {Assert.notEmpty(columnMap, "error: columnMap must not be empty", new Object[0]);return SqlHelper.retBool(this.getBaseMapper().deleteByMap(columnMap));}default boolean remove(Wrapper<T> queryWrapper) {return SqlHelper.retBool(this.getBaseMapper().delete(queryWrapper));}default boolean removeByIds(Collection<? extends Serializable> idList) {return CollectionUtils.isEmpty(idList) ? false : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(idList));}default boolean updateById(T entity) {return SqlHelper.retBool(this.getBaseMapper().updateById(entity));}default boolean update(Wrapper<T> updateWrapper) {return this.update((Object)null, updateWrapper);}default boolean update(T entity, Wrapper<T> updateWrapper) {return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));}@Transactional(rollbackFor = {Exception.class})default boolean updateBatchById(Collection<T> entityList) {return this.updateBatchById(entityList, 1000);}boolean updateBatchById(Collection<T> entityList, int batchSize);boolean saveOrUpdate(T entity);default T getById(Serializable id) {return this.getBaseMapper().selectById(id);}default List<T> listByIds(Collection<? extends Serializable> idList) {return this.getBaseMapper().selectBatchIds(idList);}default List<T> listByMap(Map<String, Object> columnMap) {return this.getBaseMapper().selectByMap(columnMap);}default T getOne(Wrapper<T> queryWrapper) {return this.getOne(queryWrapper, true);}T getOne(Wrapper<T> queryWrapper, boolean throwEx);Map<String, Object> getMap(Wrapper<T> queryWrapper);<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);default int count() {return this.count(Wrappers.emptyWrapper());}default int count(Wrapper<T> queryWrapper) {return SqlHelper.retCount(this.getBaseMapper().selectCount(queryWrapper));}default List<T> list(Wrapper<T> queryWrapper) {return this.getBaseMapper().selectList(queryWrapper);}default List<T> list() {return this.list(Wrappers.emptyWrapper());}default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {return this.getBaseMapper().selectPage(page, queryWrapper);}default <E extends IPage<T>> E page(E page) {return this.page(page, Wrappers.emptyWrapper());}default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {return this.getBaseMapper().selectMaps(queryWrapper);}default List<Map<String, Object>> listMaps() {return this.listMaps(Wrappers.emptyWrapper());}default List<Object> listObjs() {return this.listObjs(Function.identity());}default <V> List<V> listObjs(Function<? super Object, V> mapper) {return this.listObjs(Wrappers.emptyWrapper(), mapper);}default List<Object> listObjs(Wrapper<T> queryWrapper) {return this.listObjs(queryWrapper, Function.identity());}default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {return (List)this.getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());}default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {return this.getBaseMapper().selectMapsPage(page, queryWrapper);}default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {return this.pageMaps(page, Wrappers.emptyWrapper());}BaseMapper<T> getBaseMapper();Class<T> getEntityClass();default QueryChainWrapper<T> query() {return ChainWrappers.queryChain(this.getBaseMapper());}default LambdaQueryChainWrapper<T> lambdaQuery() {return ChainWrappers.lambdaQueryChain(this.getBaseMapper());}default KtQueryChainWrapper<T> ktQuery() {return ChainWrappers.ktQueryChain(this.getBaseMapper(), this.getEntityClass());}default KtUpdateChainWrapper<T> ktUpdate() {return ChainWrappers.ktUpdateChain(this.getBaseMapper(), this.getEntityClass());}default UpdateChainWrapper<T> update() {return ChainWrappers.updateChain(this.getBaseMapper());}default LambdaUpdateChainWrapper<T> lambdaUpdate() {return ChainWrappers.lambdaUpdateChain(this.getBaseMapper());}default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);}
}
6.2、添加service接口实现
package com.atsurvey.auth.service.impl;import com.atsurvey.auth.mapper.SysRoleMapper;
import com.atsurvey.auth.mapper.SysUserRoleMapper;
import com.atsurvey.auth.service.SysRoleService;
import com.atsurvey.model.system.SysRole;
import com.atsurvey.model.system.SysUserRole;
import com.atsurvey.vo.system.AssignRoleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {@Autowiredprivate SysUserRoleMapper sysUserRoleMapper;}

com.baomidou.mybatisplus.extension.service.impl.ServiceImpl这是Mybatis-Plus提供的默认Service接口实现。

6.3、测试Service接口
package com.atsurvey;import com.atsurvey.model.system.SysRole;
import com.atsurvey.system.mapper.SysRoleMapper;
import com.atsurvey.system.service.SysRoleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class SysRoleServiceTest {@Autowiredprivate SysRoleService sysRoleService;@Testpublic void testSelectList() {System.out.println(("----- selectAll method test ------"));//UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper//所以不填写就是无任何条件List<SysRole> users = sysRoleService.list();users.forEach(System.out::println);}@Testpublic void testInsert(){SysRole sysRole = new SysRole();sysRole.setRoleName("角色管理员");sysRole.setRoleCode("role");sysRole.setDescription("角色管理员");boolean result = sysRoleService.save(sysRole);System.out.println(result); //影响的行数System.out.println(sysRole); //id自动回填}@Testpublic void testUpdateById(){SysRole sysRole = new SysRole();sysRole.setId(1L);sysRole.setRoleName("角色管理员1");boolean result = sysRoleService.updateById(sysRole);System.out.println(result);}@Testpublic void testDeleteById(){boolean result = sysRoleService.removeById(2L);System.out.println(result);}@Testpublic void testSelect1() {QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();queryWrapper.ge("role_code", "role");List<SysRole> users = sysRoleService.list(queryWrapper);System.out.println(users);}@Testpublic void testSelect2() {LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.ge(SysRole::getRoleCode, "role");List<SysRole> users = sysRoleService.list(queryWrapper);System.out.println(users);}
}

三、角色管理

1、测试controller层

1.1、添加Controller
package com.atsurvey.auth.controller;import com.atsurvey.auth.service.SysRoleService;
import com.atsurvey.common.handler.ClfwzxException;
import com.atsurvey.common.result.Result;
import com.atsurvey.model.system.SysRole;
import com.atsurvey.vo.system.AssignRoleVo;
import com.atsurvey.vo.system.SysRoleQueryVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Map;@Api(tags = "角色管理")
@RestController
@RequestMapping("/admin/system/sysRole")
public class SysRoleController {@Autowiredprivate SysRoleService sysRoleService;@ApiOperation(value = "获取全部角色列表")@GetMapping("findAll")public Result<List<SysRole>> findAll() {List<SysRole> roleList = sysRoleService.list();try{int i = 10/0;}catch (Exception e){//抛出异常throw new ClfwzxException(20001,"执行了自定义异常处理...");}return Result.ok(roleList);}
}
1.2、测试Controller接口

http://localhost:8800/admin/system/sysRole/findAll

2、定义统一返回结果对象

项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更一致、轻松。

一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容

例如,我们的系统要求返回的基本数据格式如下:

列表:

{"code": 200,"message": "成功","data": [{"id": 2,"roleName": "系统管理员"}],"ok": true
}

分页:

{"code": 200,"message": "成功","data": {"records": [{"id": 2,"roleName": "系统管理员"},{"id": 3,"name": "普通管理员"}],"total": 10,"size": 3,"current": 1,"orders": [],"hitCount": false,"searchCount": true,"pages": 2},"ok": true
}

没有返回数据:

{"code": 200,"message": "成功","data": null,"ok": true
}

失败:

{"code": 201,"message": "失败","data": null,"ok": false
}
2.1、定义统一返回结果对象

操作模块:common-util

后续其他模块也会用到,故抽取到common-util模块

package com.atsurvey.common.result;import lombok.Data;/*** 全局统一返回结果类**/
@Data
public class Result<T> {//返回码private Integer code;//返回消息private String message;//返回数据private T data;public Result(){}// 返回数据protected static <T> Result<T> build(T data) {Result<T> result = new Result<T>();if (data != null)result.setData(data);return result;}public static <T> Result<T> build(T body, Integer code, String message) {Result<T> result = build(body);result.setCode(code);result.setMessage(message);return result;}public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {Result<T> result = build(body);result.setCode(resultCodeEnum.getCode());result.setMessage(resultCodeEnum.getMessage());return result;}public static<T> Result<T> ok(){return Result.ok(null);}/*** 操作成功* @param data  baseCategory1List* @param <T>* @return*/public static<T> Result<T> ok(T data){Result<T> result = build(data);return build(data, ResultCodeEnum.SUCCESS);}public static<T> Result<T> fail(){return Result.fail(null);}/*** 操作失败* @param data* @param <T>* @return*/public static<T> Result<T> fail(T data){Result<T> result = build(data);return build(data, ResultCodeEnum.FAIL);}public Result<T> message(String msg){this.setMessage(msg);return this;}public Result<T> code(Integer code){this.setCode(code);return this;}
}

统一返回结果状态信息类

下面的状态后续都会用到,所以直接引入了

package com.atsurvey.common.result;import lombok.Getter;/*** 统一返回结果状态信息类**/
@Getter
public enum ResultCodeEnum {SUCCESS(200,"成功"),FAIL(201, "失败"),SERVICE_ERROR(2012, "服务异常"),DATA_ERROR(204, "数据异常"),LOGIN_AUTH(208, "未登陆"),PERMISSION(209, "没有权限");private Integer code;private String message;private ResultCodeEnum(Integer code, String message) {this.code = code;this.message = message;}
}
2.2、改造controller方法
@GetMapping("findAll")
public Result<List<SysRole>> findAll() {List<SysRole> roleList = sysRoleService.list();return Result.ok(roleList);
}
2.3、测试接口

http://localhost:8800/admin/system/sysRole/findAll

3、knife4j

文档地址:https://doc.xiaominfo.com/

knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。

3.1、Swagger介绍

前后端分离开发模式中,api文档是最好的沟通方式。

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。

1、及时性 (接口变更后,能够及时准确地通知相关前后端开发人员)

2、规范性 (并且保证接口的规范性,如接口的地址,请求方式,参数及响应格式和错误信息)

3、一致性 (接口信息一致,不会出现因开发人员拿到的文档版本不一致,而出现分歧)

4、可测性 (直接在接口文档上进行测试,以方便理解业务)

3.2、集成knife4j

knife4j属于service模块公共资源,因此我们集成到service-uitl模块

3.2.1 添加依赖

操作模块:service-uitl

<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>

说明:guigu-auth-parent已加入版本管理

3.2.2 添加knife4j配置类

操作模块:service-uitl

package com.atsurvey.common.config.knife4j;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;import java.util.ArrayList;
import java.util.List;/*** knife4j配置信息*/
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {@Beanpublic Docket adminApiConfig(){List<Parameter> pars = new ArrayList<>();ParameterBuilder tokenPar = new ParameterBuilder();tokenPar.name("token").description("用户token").defaultValue("").modelRef(new ModelRef("string")).parameterType("header").required(false).build();pars.add(tokenPar.build());//添加head参数endDocket adminApi = new Docket(DocumentationType.SWAGGER_2).groupName("adminApi").apiInfo(adminApiInfo()).select()//只显示admin路径下的页面.apis(RequestHandlerSelectors.basePackage("com.atsurvey")).paths(PathSelectors.regex("/admin/.*")).build().globalOperationParameters(pars);return adminApi;}private ApiInfo adminApiInfo(){return new ApiInfoBuilder().title("后台管理系统-API文档").description("本文档描述了后台管理系统微服务接口定义").version("1.0").contact(new Contact("atsurvey", "http://atsurvey.com", "atsurvey@qq.com")).build();}}
3.2.3 Controller层添加注解
package com.atsurvey.system.controller;import com.atsurvey.system.service.SysRoleService;
import com.atsurvey.common.result.Result;
import com.atsurvey.model.system.SysRole;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@Api(tags = "角色管理")
@RestController
@RequestMapping("/admin/system/sysRole")
public class SysRoleController {@Autowiredprivate SysRoleService sysRoleService;@ApiOperation(value = "获取全部角色列表")@GetMapping("findAll")public Result<List<SysRole>> findAll() {List<SysRole> roleList = sysRoleService.list();return Result.ok(roleList);}
}
3.2.4、测试

http://localhost:8800/doc.html

在这里插入图片描述

4、分页查询

4.1、配置分页插件

操作模块:service-uitl,service公共资源

说明:我们将@MapperScan(“com.atsurvey.auth.mapper”)提取到该配置类上面,统一管理,启动类就不需要了。

package com.atsurvey.common.config.mp;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan("com.atsurvey.auth.mapper")
public class MybatisPlusConfig {/*** 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}@Beanpublic ConfigurationCustomizer configurationCustomizer() {return configuration -> configuration.setUseDeprecatedExecutor(false);}
}
4.2、分页controller
//条件分页查询
//page 当前页  limit 每页显示记录数
//SysRoleQueryVo 条件对象
@ApiOperation("条件分页查询")
@GetMapping("{page}/{limit}")
public Result pageQueryRole(@PathVariable Long page,@PathVariable Long limit,SysRoleQueryVo sysRoleQueryVo) {//调用service的方法实现//1 创建Page对象,传递分页相关参数//page 当前页  limit 每页显示记录数Page<SysRole> pageParam = new Page<>(page,limit);//2 封装条件,判断条件是否为空,不为空进行封装LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();String roleName = sysRoleQueryVo.getRoleName();if(!StringUtils.isEmpty(roleName)) {//封装 like模糊查询wrapper.like(SysRole::getRoleName,roleName);}//3 调用方法实现IPage<SysRole> pageModel = sysRoleService.page(pageParam, wrapper);return Result.ok(pageModel);
}

5、其他controller方法

说明:通过knife4j测试接口

@ApiOperation(value = "获取")
@GetMapping("get/{id}")
public Result get(@PathVariable Long id) {SysRole role = sysRoleService.getById(id);return Result.ok(role);
}@ApiOperation(value = "新增角色")
@PostMapping("save")
public Result save(@RequestBody @Validated SysRole role) {sysRoleService.save(role);return Result.ok();
}@ApiOperation(value = "修改角色")
@PutMapping("update")
public Result updateById(@RequestBody SysRole role) {sysRoleService.updateById(role);return Result.ok();
}@ApiOperation(value = "删除角色")
@DeleteMapping("remove/{id}")
public Result remove(@PathVariable Long id) {sysRoleService.removeById(id);return Result.ok();
}@ApiOperation(value = "根据id列表删除")
@DeleteMapping("batchRemove")
public Result batchRemove(@RequestBody List<Long> idList) {sysRoleService.removeByIds(idList);return Result.ok();
}

配置日期时间格式

application-dev.yml添加以下内容

  jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8

6、统一异常处理

6.1、制造异常

除以0

int a = 10/0;

在这里插入图片描述

我们想让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要统一异常处理。

6.2、全局异常处理
6.2.1、创建统一异常处理器

操作模块:service-util

package com.atsurvey.common.handler;import com.atsurvey.common.result.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;/*** 全局异常处理类**/
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)@ResponseBodypublic Result error(Exception e){e.printStackTrace();return Result.fail();}
}
6.2.1、测试
6.3、处理特定异常
6.3.1、添加异常处理方法

GlobalExceptionHandler.java中添加

@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public Result error(ArithmeticException e){e.printStackTrace();return Result.fail().message("执行了特定异常处理");
}
6.3.2、测试
6.4、处理自定义异常
6.4.1、创建自定义异常类
package com.atsurvey.common.execption;import com.atguigu.common.result.ResultCodeEnum;
import lombok.Data;/*** 自定义全局异常类**/
@Data
public class ClfwzxException extends RuntimeException {private Integer code;private String message;/*** 通过状态码和错误消息创建异常对象* @param code* @param message*/public ClfwzxException(Integer code, String message) {super(message);this.code = code;this.message = message;}/*** 接收枚举类型对象* @param resultCodeEnum*/public ClfwzxException(ResultCodeEnum resultCodeEnum) {super(resultCodeEnum.getMessage());this.code = resultCodeEnum.getCode();this.message = resultCodeEnum.getMessage();}@Overridepublic String toString() {return "GuliException{" +"code=" + code +", message=" + this.getMessage() +'}';}
}
6.4.2、业务中需要位置抛出
try {int a = 10/0;
}catch(Exception e) {throw new ClfwzxException(20001,"出现自定义异常");
}
6.4.3、添加异常处理方法

GlobalExceptionHandler.java中添加

@ExceptionHandler(ClfwzxException.class)
@ResponseBody
public Result error(ClfwzxExceptione){e.printStackTrace();return Result.fail().message(e.getMsg()).code(e.getCode());
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MSR810-LM快速配置通过LTE模块上网

正文共&#xff1a;1111 字 13 图&#xff0c;预估阅读时间&#xff1a;1 分钟 之前买了一个无线版本的MSR810-W&#xff08;淘了一台二手的H3C企业路由器&#xff0c;就用它来打开网络世界的大门&#xff09;&#xff0c;并整理了一份快速配置&#xff08;脚本案例来了&#x…

20240514,算法(算数生成,集合)

还有一个大案例&#xff0c;那个就不急了&#xff0c;完结撒花&#xff0c;起码C是打代码没什么大问题的完结&#xff0c;不像C&#xff0c;还要我返工/笑哭 常用算数生成算法 属于小算法&#xff0c;头文件 #include <numeric> accumulate //计算容器累计总和fill /…

霍廷格电源 Tru plasma DC3030 通快DC3040 MF3030

霍廷格电源 Tru plasma DC3030 通快DC3040 MF3030

根据后端返回下拉请求地址,前端动态请求拿到下拉数据渲染

完整代码如下&#xff1a; <template> <!-- 资源列表页 --> <div> <div> <i click"$router.go(-1)" style" color: #409eff; cursor: pointer; margin-right: 5px; font-size: 18px; " class"el-icon-back" ><…

读人工智能时代与人类未来笔记03_演变

1. 演变 1.1. 每个社会都找到了属于自己的一套适应世界的方法 1.1.1. 适应的核心&#xff0c;是有关人类心智与现实之间关系的概念 1.1.2. 人类认识周围环境的能力 1.1.2.1. 这种能力通过知识获得&#xff0c;同时也受到知识…

快速上手并行执行——《OceanBase 并行执行》 系列 7

并行执确实是一个涵盖多个层面的复杂主题&#xff0c;它需要投入一定的时间和精力来深入理解&#xff0c;才能充分掌握其功能。为了帮助初学者更快地掌握并行执行的技巧&#xff0c;我们提供了这份Quick Start&#xff0c;它适用于 OceanBase 3.1版本及以上的版本。虽然这里所…

专业PDF编辑软件Acrobat Pro DC 2022 for Mac中文版下载

Adobe Acrobat Pro DC 2022是一款PDF处理的软件&#xff0c;能够辅助MAC的用户进行PDF的各种文件上的操作&#xff0c;对于用户而言它以极为优秀和卓越的PDF体验来让用户使用起来更为的轻松一些&#xff0c;对于用户而言这款Adobe Acrobat Pro DC 2022绝对是Mac上面最佳的PDF工…

项目组GIT操作规范

分支规范 在开发过程中&#xff0c;一般会存在以下几种分支&#xff1a; main分支(master) master为主分支&#xff0c;也是用于部署生产环境的分支&#xff0c;一般由 dev 以及 fixbug分支合并&#xff0c;任何时间都不能直接修改代码。dev分支 develop 为开发分支&#xff…

C++ | Leetcode C++题解之第89题格雷编码

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> grayCode(int n) {vector<int> ret(1 << n);for (int i 0; i < ret.size(); i) {ret[i] (i >> 1) ^ i;}return ret;} };

嵌入式学习——Shell(流指针、文件读写函数)——day20

1. 标准IO和文件IO的区别 1. 标准IO是一种有缓存的IO形式&#xff08;接收了一部分内容后给到linux内核中&#xff09; 2. 文件IO是一种没有缓存的IO形式&#xff08;即刻交给linux内核&#xff0c;及时性&#xff09; 3. 标准IO是库函数,库函数可以在Windows和Linux系统中都能…

Linux下Code_Aster源码编译安装及使用

目录 软件介绍 基本依赖 其它依赖 一、源码下载 二、解压缩 三、编译安装 四、算例运行 软件介绍 Code_aster为法国电力集团&#xff08;EDF&#xff09;自1989年起开始研发的通用结构和热力耦合有限元仿真软件。Code_aster可用于力学、热学和声学等物理现象的仿真分析&…

OV通配符/泛域名SSL证书怎么获取和安装

OV通配符/泛域名SSL证书的获取和安装主要可以分为以下几个步骤&#xff1a; 一、获取证书 1. 选择服务商 选择一个提供OV通配符SSL证书的服务商&#xff0c;例如JoySSL。 2. 提交申请 在服务商网站上选择OV通配符SSL证书产品&#xff0c;填入基础信息&#xff0c;如公司名…