Ruoyi若依笔记
目标系统:若依前后分离版 3.8.5,若依不分离版 4.5.0
新建自己的模块与若依代码分隔使用
在根项目下新建模块,比如叫business
,组名是com.ruoyi
,工件名business
。特别强调,使用代码生成功能时尽量以纯小写、驼峰命名,不要加-
之类的额外字符,容易翻车。
创建后的目录结构如下
修改business
模块的pom.xml
,添加ruoyi-framework
依赖
<!-- 将依赖添加到新模块的pom.xml-->
<dependencies>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-framework</artifactId>
</dependency>
</dependencies>
在ruoyi-admin
中添加business
模块的依赖
检查根项目ruoyi
下的pom.xml
的modules
中是否正确添加了新的(包括正确移除了不存在)模块
菜单管理与代码生成的“冲突”
菜单管理可以通过非编码方式创建和管理菜单和按钮组件,但以下情况下可能会与代码生成产生冲突:
建目录A,目录A下建菜单A1,建立菜单时会让你填写路由地址、组件路径、权限字符、路由参数等,我不太明白填写后的影响,就填写并生成菜单。之后在代码生成的生成信息部分可选择上级菜单
,此时就是冲突的地方。如果选择了目录A,就会在目录A下产生两个菜单A1,如果选择菜单A1,就会在菜单A1(菜单管理创建的)下又有菜单A1(代码生成创建的)。经过分析推测是我的用法不对,猜测这两个功能应该是互相补充、互相配合的关系。
改进使用方式如下:主要思路是通过菜单管理
功能建立单纯的如目录
这样自身没有后端请求逻辑的菜单,如果目录的下级菜单没有请求逻辑也可以如此。之后使用代码生成
功能生成前后端代码,在代码生成时通过在生成信息
部分选择上级菜单
的方式,将生成的代码绑定到菜单,也就是通过菜单管理创建目录,通过代码生成创建具体菜单,过程举例:
创建目录企业管理
生成对应代码
生成代码的对应结构
对所生成的前端代码来说,刚才填写的对应关系如下
对所生成的后端代码来说,刚才填写的对应关系如下
使用生成的代码:解压缩ruoyi.zip
,运行生成的Sql脚本,将vue
目录下的文件放到前端src
目录,将main
目录下文件放到自己创建的Java模块下。再次重新分别启动前后端项目(如有意外,可以试试关闭Idea、rebuild、重启电脑)可以看到效果
引用
若依管理系统RuoYi-Vue(三):代码生成器原理和实战 https://www.cnblogs.com/kuangdaoyizhimei/p/14452736.html
查询排序(前后分离版)
由前端控制排序比较灵活,也易于实现,有关逻辑若依已经封装,后端如果懒的话都可以不做任何了解,前端实现控制如下
参数指定,在查询参数中提供约定好的参数即可,orderByColumn
指定用于排序的字段名,isAsc
指定排序规则,如
queryParams: {
pageNum: 1,
pageSize: 10,
orderByColumn: 'id',
isAsc: 'desc'
}
若依框架认识这两个参数,在后台接到查询参数时会自动按要求查询并返回结果,后端开发人员无需额外编写代码。
table组件控制,若依分离版默认使用element-ui
组件,表格组件table
提供了丰富的api,官方文档中有关于排序的使用描述,此处仅记录关键部分。table
组件的排序能力分两种,一种是不需要后端参与的,仅对前端中已经获得的数据进行排序,要达到这个效果对列设置sortable
即可,该列就会出现上下小箭头,点击列,显示的数据即会改变排序顺序。
<el-table-column label="Id" align="center" sortable prop="id"/>
第二种,真正的前端请求后端排序,首先将sortable
改为sortable=custom
,然后给table
组件增加sort-change
事件的侦听,在事件回调中向后台发起请求,实现“真”排序。
<el-table @sort-change="handleSortChange">
<el-table-column label="Id" align="center" sortable="custom" prop="id"/>
</el-table>
...
methods: {
// options.prop: 引发排序事件的列绑定的 prop 属性
// options.order: 排序顺序,null-默认/不正不反/没有箭头被点亮,ascending-正序/箭头向上,descending-倒序/箭头向下
handleSortChange(options){
// 向后端发起请求
}
}
多数据源配置
首先,在配置文件spring:datasource:druid
中增加数据源配置
spring:
datasource:
druid:
master: xxx
slavebi:
enabled: true
url: jdbc:sqlserver://19.19.19.19:1433;DatabaseName=mydb;
username: root
password: 123456
在ruoyi-common\enums\DataSourceType
文件中增加对应枚举声明
public enum DataSourceType{
MASTER,
SLAVEBI
}
在ruoyi-framework\config\properties\DruidConfig
文件中增加对应方法
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource slavebiDataSource(DruidProperties druidProperties)
{
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean(name = "dynamicDataSource")
@Primary
public DynamicDataSource dataSource(DataSource masterDataSource)
{
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
setDataSource(targetDataSources, DataSourceType.SLAVEBI.name(), "slavebiDataSource");
return new DynamicDataSource(masterDataSource, targetDataSources);
}
/**
* 设置数据源
*
* @param targetDataSources 备选数据源集合
* @param sourceName 数据源名称
* @param beanName bean名称
*/
public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
{
try
{
DataSource dataSource = SpringUtils.getBean(beanName);
targetDataSources.put(sourceName, dataSource);
}
catch (Exception e)
{
}
}
在Service、Mapper或方法上使用@DataSource
注解的方式切换数据源来使用
/**
* SmartBI 查询相关Mapper接口
* @author
*/
@Repository
@DataSource(value = DataSourceType.SLAVEBI)
public interface ContractSmartBIMapper {
/**
* 从SmartBI查询采购订单和相关预算信息
* @param purchaseOrderDocNo 合同(采购订单)号
* @return
*/
public List<ContractBudgetBo> selectContractBudgetBoList(String purchaseOrderDocNo);
}
自定义拦截器
首先自定义类实现HandlerInterceptor
,在实现WebMvcConfigurer
的实现类的addInterceptors
方法中加入自定义拦截器实现类的实例即可
package com.ruoyi.framework.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* 自定义拦截器
*/
@Component
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {
System.out.println("调用Controller方法之前");
if(handler instanceof HandlerMethod){
System.out.println("CustomInterceptor preHandle: do preHandle");
if(1==1){
return false;
}
}else{
System.out.println("CustomInterceptor preHandle: super preHandle");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
return true;
}
@Override
public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Object modelAndView) throws Exception {
System.out.println("调用Controller方法之后页面渲染之前执行");
}
@Override
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("调用Controller方法之后页面渲染之后执行");
}
}
配置拦截器
@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{
@Autowired
private RepeatSubmitInterceptor repeatSubmitInterceptor;
@Autowired
private CustomInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(myInterceptor).addPathPatterns("/**");
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
}
}
控制台输出效果