在 ruoyi-admin 引入 Spring3.0 版本
RuoYiApplication添加积木扫描目录
@SpringBootApplication(scanBasePackages={"org.dromara","org.jeecg.modules.jmreport" })
public class DromaraApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(DromaraApplication.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
System.out.println("(♥◠‿◠)ノ゙ RuoYi-Vue-Plus启动成功 ლ(´ڡ`ლ)゙");
}
}
SecurityConfig拦截排除
在 application.yml 中的 security 配置中添加 /jmreport/**
配置启动属性
配置请求类
为了方便我放在了org.dromara.web.controller.jimu 实现
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
@RequestMapping("/report/jimu")
public class JimuController {
@Autowired
Environment environment;
@GetMapping("/index")
@SaCheckPermission("report:jimu:index")
public String index(){
return environment.getProperty("jimu-report.url")+"/jmreport/list";
}
@GetMapping("/view")
@SaCheckPermission("report:jimu:view")
public String view(){
return environment.getProperty("jimu-report.url")+"/jmreport/view";
}
}
前端API 请求
import request from '@/utils/request';
//积木报表接口
export const indexUrl = (query?: any) =>
request({
url: '/report/jimu/index',
method: 'get',
});
export const view = (query?: any) =>
request({
url: '/report/jimu/view',
method: 'get',
});
前端配置报表设计器 List 页面
此界面对应的是积木报表/jmreport/list
<template>
<div v-loading="loading" :style="`height:${height}px;`">
<iframe :src="src" frameborder="no" style="width: 100%; height: 100%" scrolling="auto" />
</div>
</template>
<script setup>
import { onMounted, ref, watchEffect } from 'vue';
import { useRoute } from 'vue-router';
import { getToken } from '@/utils/auth';
import { indexUrl } from '@/api/report/jimu';
const loading = ref(true);
const height = ref(document.documentElement.clientHeight - 94.5);
const src = ref('');
// 初始化数据
onMounted(() => {
fetchSrc();
setTimeout(() => {
loading.value = false;
}, 230);
// 监听窗口大小变化
const handleResize = () => {
height.value = document.documentElement.clientHeight - 94.5;
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
});
// 获取 iframe 源地址
const fetchSrc = async () => {
try {
const response = await indexUrl();
src.value = `${response}?token=${getToken()}`;
} catch (error) {
console.error('Failed to fetch src:', error);
}
};
// 监听路由变化
const route = useRoute();
watchEffect(() => {
fetchSrc();
});
</script>
前端配置报表 View 页面
此界面对应的是积木报表/jmreport/view
<template>
<div v-loading="loading" :style="`height:${height}px;`">
<iframe :src="src" frameborder="no" style="width: 100%; height: 100%" scrolling="auto" />
</div>
</template>
<script setup>
import { onMounted, ref, watchEffect } from 'vue';
import { useRoute } from 'vue-router';
import { getToken } from '@/utils/auth';
import { view } from '@/api/report/jimu';
const loading = ref(true);
const height = ref(document.documentElement.clientHeight - 94.5);
const src = ref('');
// 初始化数据
onMounted(() => {
fetchSrc();
setTimeout(() => {
loading.value = false;
}, 230);
// 监听窗口大小变化
const handleResize = () => {
height.value = document.documentElement.clientHeight - 94.5;
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
});
// 获取 iframe 源地址
const fetchSrc = async () => {
try {
//获取路由参数reportId
const reportId = useRoute().path.substring(useRoute().path.lastIndexOf("/")+1)
const response = await view();
src.value = `${response}/${reportId}?token=${getToken()}`;
} catch (error) {
console.error('Failed to fetch src:', error);
}
};
// 监听路由变化
const route = useRoute();
watchEffect(() => {
fetchSrc();
});
</script>
前端 菜单配置
前端配置两个按钮权限
此处两权限必须与后端请求类一致
添加 Token 校验
实现JimuReportTokenService 类
为了方便我放在了org.dromara.web.controller.jimu 实现
package org.dromara.web.controller.jimu;
import cn.hutool.core.util.ObjectUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
@Component
@AllArgsConstructor
public class JimuReportTokenService implements JmReportTokenServiceI {
@Override
public String getToken(HttpServletRequest request) {
return getTokenByRequest(request);
}
@Override
public String getToken() {
return JmReportTokenServiceI.super.getToken();
}
@Override
public String getUsername(String s) {
LoginUser loginUser = LoginHelper.getLoginUser();
return loginUser.getUsername();
}
@Override
public String[] getRoles(String s) {
return new String[0];
}
@Override
public Boolean verifyToken(String s) {
//此处不作判断在JmReporListInterceptor和JmReporViewInterceptor拦截器中已校验
return true;
}
// @Override
// public Boolean verifyToken(String s) {
// LoginUser loginUser = LoginHelper.getLoginUser(s);
// if(ObjectUtil.isNotEmpty(loginUser)){
// if(LoginHelper.isSuperAdmin(loginUser.getUserId())){
// return true;
// }else {
// //获取权限集合
// Set<String> permissions = loginUser.getMenuPermission();
// //如果拥有设计器的权限,则无需view权限,也可以通过校验
// if(permissions != null && permissions.contains("report:jimu:list")) {
// return true;
// } else if (permissions != null && permissions.contains("report:jimu:view")) {
// return true;
// }
// return false;
// }
// }
// return false;
// }
@Override
public Map<String, Object> getUserInfo(String token) {
return JmReportTokenServiceI.super.getUserInfo(token);
}
@Override
public HttpHeaders customApiHeader() {
return JmReportTokenServiceI.super.customApiHeader();
}
@Override
public String getTenantId() {
return JmReportTokenServiceI.super.getTenantId();
}
/**
* 获取 request 里传递的 token
*
* @param request
* @return
*/
public static String getTokenByRequest(HttpServletRequest request) {
String parameter = request.getParameter("token");
String header = request.getHeader("token");
if (parameter == null && header == null) {
parameter = request.getHeader("Authorization");
}
return parameter != null ? parameter : header;
}
}
实现对设计器 List 和视图 View 的监听器
需要在ruoyi-common-web 实现
package org.dromara.common.web.interceptor;
import cn.hutool.json.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Set;
/**
* 拦截积木报表设计器访问路由,校验权限
*
*/
public class JmReportListInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setContentType("text/html; charset=UTF-8");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String token = request.getParameter("token");
LoginUser loginUser = LoginHelper.getLoginUser(token);
if (loginUser != null) {
if(LoginHelper.isSuperAdmin(loginUser.getUserId())){
return true;
}else {
//获取权限集合
Set<String> permissions = loginUser.getMenuPermission();
//获取权限集合
//如果拥有设计器的权限,则无需view权限,也可以通过校验
if(permissions != null && permissions.contains("report:jimu:list")) {
return true;
}
}
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 200);
jsonObject.put("msg", "参数错误或无权访问数据");
response.getWriter().println(jsonObject);
return false;
}
}
package org.dromara.common.web.interceptor;
import cn.hutool.json.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Set;
/**
* 拦截积木报表查看访问路由,校验权限
*
*/
public class JmReportViewInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setContentType("text/html; charset=UTF-8");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String token = request.getParameter("token");
LoginUser loginUser = LoginHelper.getLoginUser(token);
if (loginUser != null) {
if(LoginHelper.isSuperAdmin(loginUser.getUserId())){
return true;
}else {
//获取权限集合
Set<String> permissions = loginUser.getMenuPermission();
//获取权限集合
//如果拥有设计器的权限,则无需view权限,也可以通过校验
if (permissions != null && permissions.contains("report:jimu:view")) {
//需要同时判断对应表单权限
//一般是通过报表菜单点击进来的,校验是否有对应报表的权限:report:jimu:view:{reportId}
//http../jmreport/view/717968580806651904,则reportId = 717968580806651904
String reportId = StringUtils.substringAfterLast(request.getRequestURI(), "/");
//report:jimuView 需要与全端的权限保持一致
String viewPerm = "report:jimuView:" + reportId;
if (permissions != null && permissions.contains(viewPerm)) {
return true;
}
}
}
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 200);
jsonObject.put("msg", "参数错误或无权访问数据");
response.getWriter().println(jsonObject);
return false;
}
}
在ResourcesConfig 添加监听
registry.addInterceptor(new JmReportViewInterceptor()).addPathPatterns("/jmreport/view/**");
registry.addInterceptor(new JmReportListInterceptor()).addPathPatterns("/jmreport/list/**");
注意ruoyi-common-web 需要引入ruoyi-common-satoken
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-satoken</artifactId>
</dependency>