1. 按JimuReport官方文档进行基本集成

  • Ruoyi-Vue版本:3.8.1
  • JimuReport版本:1.5.2

基本的集成,JimuReport官方文档有提供教程,这里不再重复。
在这里插入图片描述

2. 排除Mogo配置类

如果启动时报了以下错误:

在这里插入图片描述

ruoyi-admin启动类中,将Mogo配置类排除即可。

在这里插入图片描述

3. 自定义项目前缀

application.yml文件中,自定义项目前缀(主要用于菜单集成)。

jeecg :
    jmreport:
        #自定义项目前缀,必须与前端 process.env.VUE_APP_BASE_API 的值一致
        customPrePath: /dev-api

4. 报表设计器Token校验及菜单集成

4.1 后端开发配置

报表设计器权限校验关键点:

  • 每次校验时,需要刷新Token有效期,否则有可能出现报表设计一半,结果Token过期了,导致保存不了,重新登录后,可能得重新重头开始设计的情况。
  • 判断当前角色是不是超管,如果是,则无需进行鉴权,直接通过。
  • 每个用户都有Token,但是除了超管之外,其他所有人都需要判断是否有报表设计器菜单的权限,如果没有,则不让通过。
  • 实现:com.ruoyi.framework.web.service.JimuReportTokenService.verifyToken()

1)在com.ruoyi.framework.web.service.TokenService中添加两个方法

/**
 * 通过Token获取用户身份信息
 *
 * @return 用户信息
 */
public LoginUser getLoginUser(String token) {
  if (StringUtils.isNotEmpty(token)){
    if (token.startsWith(Constants.TOKEN_PREFIX)) {
      token = token.replace(Constants.TOKEN_PREFIX, "");
    }
    try{
      Claims claims = parseToken(token);
      // 解析对应的权限以及用户信息
      String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
      String userKey = getTokenKey(uuid);
      LoginUser user = redisCache.getCacheObject(userKey);
      return user;
    }catch (Exception e){ }
  }
  return null;
}

/**
 * Token对应的Header名称
 *
 * @return
 */
public String getHeader() {
    return header;
}

2)添加JimuReportTokenService类,实现接口 JmReportTokenServiceI

package com.ruoyi.framework.web.service;

import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.StringUtils;
import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 自定义积木报表鉴权(如果不进行自定义,则所有请求不做权限控制)
 *
 * @Author Zack
 * @Date 2022/8/11 9:45
 */
@Component
public class JimuReportTokenService implements JmReportTokenServiceI {

    @Autowired
    private TokenService tokenService;

    @Override
    public String getToken(HttpServletRequest request) {
        //先从url参数中取,若没有,再从header中取
        String paramToken = request.getParameter("token");
        String headerToken = request.getHeader("token");
        if (StringUtils.isEmpty(paramToken)) {
            paramToken = headerToken;
        }
        LoginUser loginUser = tokenService.getLoginUser(paramToken);
        if (loginUser != null) {
            return paramToken;
        }
        return "";
    }

    @Override
    public String getUsername(String token) {
        LoginUser loginUser = tokenService.getLoginUser(token);
        return loginUser.getUsername();
    }

    /**
     * 校验设计器权限
     * @param token
     * @return
     */
    @Override
    public Boolean verifyToken(String token) {
        LoginUser loginUser = tokenService.getLoginUser(token);
        if (StringUtils.isNotNull(loginUser)) {
            //刷新Token有效期
            tokenService.refreshToken(loginUser);
            //超管不需要鉴权
            if(loginUser.getUser() != null && loginUser.getUser().isAdmin()){
                return true;
            }else{
                //校验菜单权限
                Set<String> permissions = loginUser.getPermissions();
                if(permissions != null && permissions.contains("report:jimu:list")){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 系统上下文变量(http://report.jeecg.com/2159712)
     * @param token
     * @return
     */
    @Override
    public Map<String, Object> getUserInfo(String token) {
        Map<String, Object> map = new HashMap(5);
        LoginUser loginUser = tokenService.getLoginUser(token);
        //设置用户名
        map.put(SYS_USER_CODE, loginUser.getUsername());
        //设置部门编码
        map.put(SYS_ORG_CODE, loginUser.getDeptId());
        // 将所有信息存放至map 解析sql/api会根据map的键值解析
        return map;
    }

    @Override
    public HttpHeaders customApiHeader() {

        HttpHeaders header = new HttpHeaders();

        //主要用于API数据源。默认给API数据源的header中携带上Token。
        //如使用当前项目的API,则需要在header中携带Authorization头
        header.add(tokenService.getHeader(), getToken());

        header.add("token", getToken());
        header.add("X-Access-Token", getToken());
        return header;
    }
}

4.2 前端设计器菜单集成

1)新建vue,使用iFrame集成设计器页面。

在这里插入图片描述

<template>
  <i-frame :src="openUrl" id="jimuReportFrame" />
</template>
 
<script>
import { getToken } from '@/utils/auth'
import iFrame from "@/components/iFrame/index";
 
export default {
  name: 'JimuReportDesign',
  components: { iFrame },
  data() {
    return {
      openUrl: process.env.VUE_APP_BASE_API + '/jmreport/list?token=Bearer ' +  getToken()
    }
  },
}
</script>
 
<style scoped>
 
</style>

2)菜单配置

image-20220817135801152

3)完成

在这里插入图片描述


5. 报表查看器Token校验及菜单集成

报表查看权限校验关键点:

  • 判断当前角色是不是超管,如果是,则无需进行鉴权,直接通过。
  • 判断当前用户是否有设计器的权限,如果有,那也无需进行报表查看权限的校验
  • 除此之外,其他所有人都需要判断是否有对应报表的查看权限,即只允许查看被授权的报表。
    • 每个Jimu报表都有一个报表ID,在菜单权限标识符中,加上该ID,即可做到区分不同报表的权限控制。

5.1 后端开发配置

新增拦截规则JmReportInterceptor,实现HandlerInterceptor类,重写preHandle方法

package com.ruoyi.framework.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Set;

/**
 * 拦截积木报表查看访问路由,校验权限
 *
 * @Author Zack
 * @Date 2022/8/12 15:05
 */
@Component
public class JmReportInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String token = request.getParameter("token");
        LoginUser loginUser = tokenService.getLoginUser(token);
        if (loginUser != null) {
            //超管不需要鉴权
            if(loginUser.getUser() != null && loginUser.getUser().isAdmin()){
                return true;
            }else{
                //获取权限集合
                Set<String> permissions = loginUser.getPermissions();
                //如果拥有设计器的权限,则无需view权限,也可以通过校验
                if(permissions != null && permissions.contains("report:jimu:list")){
                    return true;
                }
                //其余情况,一般是通过报表菜单点击进来的,校验是否有对应报表的权限:report:jimu:view:{reportId}
                //http../jmreport/view/717968580806651904,则reportId = 717968580806651904
                String reportId = StringUtils.substringAfterLast(request.getRequestURI(), "/");
                String viewPerm = "report:jimu:view:" + reportId;
                if(permissions != null && permissions.contains(viewPerm)){
                    return true;
                }
            }
        }
        AjaxResult ajaxResult = AjaxResult.error("参数错误或没有该报表的访问权限!");
        ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
        return false;
    }
}

将拦截规则添加到配置中com.ruoyi.framework.config.ResourcesConfig.addInterceptors

在这里插入图片描述

5.2 前端报表查看菜单集成

1)新建vue,使用iFrame集成报表查看页面。

<template>
  <i-frame :src="openUrl" />
</template>
 
<script>
import { getToken } from '@/utils/auth'
import iFrame from "@/components/iFrame/index";
 
export default {
  name: 'JimuReportView',
  components: { iFrame },
  data() {
    return {
      openUrl: '',
    }
  },
  created() {
    const reportId = this.$route.path.substring(this.$route.path.lastIndexOf("/")+1)
    this.openUrl = process.env.VUE_APP_BASE_API + '/jmreport/view/' + reportId + '?token=Bearer ' +  getToken()
  }
}
</script>
 
<style scoped>
 
</style>

2)菜单配置

image-20220817135801152
  • 路由地址:jimu/view/{reportId},reportId就是预览界面URL中的报表ID

  • 权限字符:report:jimu:view:{reportId},必须与后台权限校验时的文本一致。

在这里插入图片描述

3)完成

在这里插入图片描述

Logo

快速构建 Web 应用程序

更多推荐