您的位置:

ruoyi-vue-pro 开发指南

一、简介

ruoyi-vue-pro 是一款基于 SpringBoot2.x 全家桶实现、Vue、Element UI 的后台管理系统模板,提供模板功能和CRUD代码生成,并且支持多租户系统、多数据源系统,可浏览器缓存、工作流、十强排行榜、代码生成等常用开发功能。

在本章节中,我们将介绍该系统的基本架构和运行环境。

二、系统架构

本系统的架构基于传统的前后端分离架构模式,采用以下技术栈:

  • 前端采用 Vue + Element + Axios + Webpack;
  • 后端采用 SpringBoot2.x + MyBatis-Plus + Shiro + Swagger-UI + Log4j2。

三、运行环境

运行该项目需要满足以下环境:

  • JDK8+
  • Maven 3.0+
  • MySQL 5.5+
  • Node.js 10+

四、项目结构

本系统的项目结构如下:

ruoyi-vue-pro/
  ├── ruoyi-admin/  后台管理模块
  ├── ruoyi-common/ 客户端、服务端公共模块
  ├── ruoyi-framework/ 框架核心模块
  ├── ruoyi-generator/ java代码自动生成模块
  ├── ruoyi-quartz/ 定时任务模块
  ├── ruoyi-system/ 后台管理业务模块
  ├── ruoyi-tools/ 系统工具模块
  └── src/  Vue前端代码

五、代码示例

1. Mybatis-Plus 更改系统默认表名确定方法

在项目中使用Mybatis-Plus的时候,默认情况下表名和实体类名必须一一对应,否则-会出现"无法找到该实体"的错误。在系统多数据源的时候,这种情况更加明显。

/**
* 代码生成前缀配置,表名以sys_开头才生成代码
*/
strategy.setTablePrefix(new String[] { "sys_" });

/**
*根据数据库表获取对应实体类
*/
@Override
public String tableToJava(String tableName) {
    if (tableName.startsWith("sys_")) {
        return upperTableName2Camel(tableName.replaceFirst("sys_", ""));
    } else if (tableName.startsWith("gen_")) {
        return upperTableName2Camel(tableName.replaceFirst("gen_", "Gen"));
    } else if (tableName.startsWith("qrtz_")) {
        return upperTableName2Camel(tableName.replaceFirst("qrtz_", "Qrtz"));
    } else {
        return upperTableName2Camel(tableName);
    }
}

2. 自定义异常处理

异常处理是Web应用开发中非常重要的一环,当系统出现异常时,我们需要有一个统一的异常处理机制。在本项目中,我们通过继承DefaultHandlerExceptionResolver,并重写它的resolveException()方法实现异常处理。

@RestControllerAdvice
public class GlobalExceptionHandler extends DefaultHandlerExceptionResolver {

    @Autowired
    private MessageSource messageSource;

    /**
    * 处理业务异常
    */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R businessException(BusinessException e) {
        String message = messageSource.getMessage(e.getMessage(), null, LocaleContextHolder.getLocale());
        return R.error(message);
    }

    /**
    * 处理未知异常
    */
    @Override
    protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        logger.error("系统内部异常,异常信息:", ex);

        /**
        * 对于未知异常,只返回“系统内部异常”这个提示信息
        */
        String message = messageSource.getMessage("error.internal.server", null, LocaleContextHolder.getLocale());
        return new ResponseEntity<>(R.error(message), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}


3. 多租户系统实现

本系统支持多租户,在开发过程中每个公司可以使用一个数据库,将每个公司的相关数据存放在各自的数据库中。我们在引入Mybatis-Plus后,通过继承MybatisSqlInterceptor实现多租户的切换。

@Configuration
@MapperScan("com.ruoyi.system.mapper")
public class MybatisPlusConfig {

    @Autowired
    private RuoYiConfig ruoyiConfig;

    /**
    * 多租户方案之一:schema模式
    */
    @Bean
    public MybatisSqlInterceptor mybatisSqlInterceptor() {
        return new MybatisSqlInterceptor() {
            @Override
            public void prepare(SqlMappedStatement mappedStatement, Object parameter) {
                if (SecurityUtils.getMultiTenantId() != null) {
                    final String tenantId = SecurityUtils.getMultiTenantId();
                    if (StringUtils.isNotBlank(tenantId)) {
                        String originalSql = mappedStatement.getSql();
                        StringBuilder sqlBuilder = new StringBuilder("SET SCHEMA '")
                                .append(tenantId.toLowerCase())
                                .append("';");
                        sqlBuilder.append(originalSql);

                        setPreparedSql(originalSql);
                        setTargetSql(sqlBuilder.toString());
                    }
                }
            }
        };
    }

    /**
    * 多租户方案之二:动态表名
    */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new DynamicTableNameInnerInterceptor());
        return interceptor;
    }
}

4. Vue + Element UI 实现图标操作

Vue + Element UI 可以通过依赖 fontawesome 实现图标操作。在这里我们可以选择几种方式来实现图标的引用:

  1. 引用CDN上面的fontawesome图标库
  2.     <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
      
  3. 下载fontawesome文件到本地,然后引用本地文件
  4.     <link rel="stylesheet" href="~/fontawesome/css/font-awesome.min.css">
      
  5. 使用vue-awesome作为插件,安装这个插件,就可以很方便地在vue中使用fontawesome图标库的各种图标了。
  6.     npm install --save @fortawesome/fontawesome-svg-core
        npm install --save @fortawesome/free-solid-svg-icons
        npm install --save @fortawesome/vue-fontawesome
      
        
         
    
        <script>
          import Vue from 'vue'
          import { library } from '@fortawesome/fontawesome-svg-core'
          import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
          import { faUser } from '@fortawesome/free-solid-svg-icons'
    
          // 通过library方法引入想要使用的图标
          library.add(faUser)
    
          Vue.component('font-awesome-icon', FontAwesomeIcon)
        </script>
      

5. Swagger-UI 自动生成API文档

Swagger-UI 可以根据我们代码中的注解自动生成 API 文档。在本项目中,我们可以通过以下配置实现:

/**
* swagger配置
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
    /**
    * 注入系统基础配置
    */
    @Autowired
    private RuoYiConfig ruoyiConfig;

    @Bean
    public Docket createRestApi() {
        // 添加全局头部信息
        ParameterBuilder parameterBuilder = new ParameterBuilder();
        List parameters = new ArrayList<>();
        parameterBuilder.name("Authorization")
                .description("令牌")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false).build();
        parameters.add(parameterBuilder.build());

        // API文档基本信息配置
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(parameters)
                .securityContexts(Collections.singletonList(securityContext()))
                .securitySchemes(Collections.singletonList(securityScheme()));
    }

    /**
    * API文档基本信息配置
    */
    public ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("若依系统接口文档")
                .description("若依管理系统后台接口文档")
                .contact(new Contact(ruoyiConfig.getName(), null, null))
                .version("版本号:" + ruoyiConfig.getVersion())
                .build();
    }

    /**
    * 通过Swagger解决token问题
    */
    public SecurityScheme securityScheme() {
        return new ApiKey("Token", "token", "header");
    }

    /**
    * 通过Swagger解决token问题
    */
    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(Arrays.asList(new SecurityReference("Token", new AuthorizationScope[]{new AuthorizationScope("global", "")})))
                .build();
    }
}

    

六、总结

本文主要介绍了ruoyi-vue-pro的基本架构和运行环境、项目结构、以及多个方面的代码示例。通过学习以上内容,我们可以更好地理解和使用该系统,从而提高我们的开发效率和协同工作能力。

顶部