ruoyi使用笔记

1.限流处理 @RateLimiter

@PostMapping("/createOrder")
@ApiOperation("创建充值订单")
@RateLimiter(key = CacheConstants.REPEAT_SUBMIT_KEY,time = 10,count = 1,limitType = LimitType.IP)
public R createOrder(@RequestBody Form form) {
    //业务处理
    return R.ok(order.getOrderNo());
}

2.@RepeatSubmit 防止重复提交

@RepeatSubmit
@PostMapping("/createOrder")
@ApiOperation("创建充值订单")
public R createOrder(@RequestBody TCommissionOrderForm form) {
    //业务处理
    return R.ok(order.getOrderNo());
}

3.数据字典使用

(1)定义

export default {
  dicts: ['dai_li', 'sys_yes_no'],

(2)列表获取

<el-table-column label="审核状态" align="center" prop="status">
  <template v-slot:="scope">
    <dict-tag :options="dict.type.sys_yes_no" :value="scope.row.status"/>
  </template>
</el-table-column>

(3)查询/新增/编辑

<el-form-item label="等级" prop="agentGrade">
  <el-select v-model="queryParams.agentGrade" placeholder="请选择代理等级" clearable>
    <el-option
      v-for="dict in dict.type.dai_li"
      :key="dict.value"
      :label="dict.label"
      :value="dict.value"
    />
  </el-select>
</el-form-item>

(4)js内获取

typeFormat(agentGrade) {
  var that=this;
  this.dict.type.dai_li.forEach(function (i){
    if (i.value==agentGrade){
      that.form.agentGradeFy=i.label;
    }
  })
},

4.图片

limit限制上传图片数量

<el-form-item label="图片" prop="coverUrl">
  <image-upload :limit="1" v-model="form.coverUrl" :width="80" :height="80"/>
</el-form-item>

5.下拉框长度比输入框短的处理办法

style=“width: 100%”

<el-form-item label="管理者性别" prop="sex">
  <el-select v-model="form.sex" style="width: 100%" disabled placeholder="请选择管理者性别">
    <el-option
      v-for="dict in dict.type.sys_user_sex"
      :key="dict.value"
      :label="dict.label"
      :value="dict.value"
    ></el-option>
  </el-select>
</el-form-item>

6.打开一个新的弹窗列表

(1)父页面

<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  <template v-slot="scope">
    <el-button
      size="mini"
      type="text"
      icon="el-icon-info"
      @click="openImportTable(scope.row)">订单明细</el-button>
  </template>
</el-table-column>
<import-table ref="import"/>

<script>
import importTable from "@/views/system/shopOrder/tjIndex"
export default {
  components:{importTable},
}
methods: {
	/** 打开导入表弹窗 */
	openImportTable(row) {
	  this.$refs.import.show(row);
	},
}
</script>

(2)子页面

A.el-dialog 把页面代码包起来

<el-dialog title="订单明细" :visible.sync="visible" width="70%" top="1vh" append-to-body>
</el-dialog>

B.用于父页面调用

methods: {
   // 显示弹框
   show(row) {
     this.shopManageId=row.shopId
     this.goodsCommodityId=row.goodsCommodityId
     this.getList();
     this.visible = true;
   },
}

C.完整代码

<template>
  <el-dialog title="订单明细" :visible.sync="visible" width="70%" top="1vh" append-to-body>
    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
      <el-form-item label="订单号" prop="orderNo">
        <el-input style="width: 155px;" v-model="queryParams.orderNo" placeholder="请输入订单号" clearable @keyup.enter.native="handleQuery"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <el-table v-loading="loading" :data="shopOrderList">
      <el-table-column label="订单号" align="center" prop="orderNo" width="150" :show-overflow-tooltip="true"/>
    </el-table>
    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
    <div slot="footer" class="dialog-footer">
      <el-button @click="visible = false">关 闭</el-button>
    </div>
  </el-dialog>
</template>

<script>
import { listShopOrder } from "@/api/system/shopOrder";

export default {
  name: "ShopOrder",
  dicts: ['t_shop_order_delivery', 'comm_pay', 't_shop_order_status'],
  data() {
    return {
      // 遮罩层
      loading: true,
      // 选中数组
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      // 显示搜索条件
      showSearch: true,
      // 总条数
      total: 0,
      // 商品订单表格数据
      shopOrderList: [],
      // 弹出层标题
      title: "",
      // 是否显示弹出层
      visible: false,
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        orderNo: null,
        shopManageId: null,
        sysUserId: null,
        addressId: null,
        goodsCommodityId: null,
        num: null,
        totalPrice: null,
        price: null,
        orderPrice: null,
        status: null,
        payWay: null,
        outTradeNo: null,
        deliveryWay: null,
        payTime: null,
        cancelTime: null,
        fhTime: null,
      },
      // 表单参数
      form: {},
      shopManageId:null,
      goodsCommodityId:null,
    };
  },
  methods: {
    // 显示弹框
    show(row) {
      this.shopManageId=row.shopId
      this.goodsCommodityId=row.goodsCommodityId
      this.getList();
      this.visible = true;
    },
    /** 查询商品订单列表 */
    getList() {
      this.queryParams.shopManageId=this.shopManageId
      this.queryParams.goodsCommodityId=this.goodsCommodityId
      this.queryParams.status='tj'
      this.loading = true;
      listShopOrder(this.queryParams).then(response => {
        this.shopOrderList = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    },
    // 表单重置
    reset() {
      this.form = {
        id: null,
        createBy: null,
        createTime: null,
        updateBy: null,
        updateTime: null,
        delFlag: null,
        orderNo: null,
        shopManageId: null,
        sysUserId: null,
        addressId: null,
        goodsCommodityId: null,
        num: null,
        totalPrice: null,
        price: null,
        orderPrice: null,
        status: null,
        payWay: null,
        outTradeNo: null,
        deliveryWay: null,
        payTime: null,
        cancelTime: null,
        fhTime: null,
        remark: null
      };
      this.resetForm("form");
    },
    /** 搜索按钮操作 */
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    /** 重置按钮操作 */
    resetQuery() {
      this.resetForm("queryForm");
      this.handleQuery();
    },
  }
};
</script>

(3)效果

在这里插入图片描述

7.偌依免登录访问页面,不影响前端框架正常登录访问,直接用链接免登录访问

(1)SecurityConfig 加入需要访问得接口

.antMatchers("/admin/vel/*").permitAll()

(2)Controller 去掉 @PreAuthorize

(3)src -> router -> index.js

注意:/find/vdlH5 不要跟框架里面的一致,自定义一个即可

// 公共路由
export const constantRoutes = [
  {
    path: '/find/vdlH5',
    component: () => import('@/views/system/find/index'),
    hidden: true
  },
}

(4)src -> permission.js

白名单加入第三步定义的path:‘/find/vdlH5’

const whiteList = ['/login', '/register','/find/vdlH5']

参考:https://www.cnblogs.com/huashenyin/p/16122113.html

8.springboot升级

https://blog.csdn.net/qq_44403239/article/details/138078084

除了以上步骤之外

(1)升级了两个xml

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-framework-bom</artifactId>
    <version>6.1.6</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>6.1.6</version>
</dependency>

(2)RepeatSubmitInterceptor

使用jakarta

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

9.自定义文件保存目录

(1)使用 file-url=“apk”

<el-form-item label="apk文件" prop="fileUrl">
  <file-upload v-model="form.fileUrl" file-url="apk"/>
</el-form-item>

(2)FileUpload组件

<el-upload :data="fileData">

<script>
	props: {
	    //自定义上传路径
	    fileUrl:{
	      type:String,
	      default:null,
	    }
    },
   data() {
    return {
      fileData:{},
    };
  },
  methods: {
    // 上传前校检格式和大小
    handleBeforeUpload(file) {
      this.fileData.fileUrl=this.fileUrl;
      this.$modal.loading("正在上传文件,请稍候...");
      this.number++;
      return true;
    },
  }
</script>

(3)后端

/**
* 通用上传请求(单个)
*/
@PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file, FileForm form) {
   try {
       // 上传文件路径
       String filePath = DCQQConfig.getUploadPath(form.getFileUrl());
       // 上传并返回新文件名称
       String fileName = FileUploadUtils.upload(filePath, file);
       String url = serverConfig.getUrl() + fileName;
       AjaxResult ajax = AjaxResult.success();
       ajax.put("url", url);
       ajax.put("fileName", fileName);
       ajax.put("newFileName", FileUtils.getName(fileName));
       ajax.put("originalFilename", file.getOriginalFilename());
       return ajax;
   } catch (Exception e) {
       return AjaxResult.error(e.getMessage());
   }
}
 /**
 * 获取上传路径
 */
public static String getUploadPath()
{
    return getProfile() + "/upload";
}

/**
 * 获取上传路径
 * @param fileUrl 自定义路径
 * @return
 */
public static String getUploadPath(String fileUrl){
    if (StringUtils.isBlank(fileUrl)){
        return getUploadPath();
    }
    return getProfile() + "/"+fileUrl;
}

(4)效果

在这里插入图片描述

10.获取用户登录状态

/**
 * 安全服务工具类
 *
 * @author ruoyi
 */
public class SecurityUtils {
    /**
     * 获取用户登录状态:true已登录,false未登录
     **/
    public static boolean isLogin() {
        Object principal = getAuthentication().getPrincipal();
        if (principal.toString().equals("anonymousUser")){
            return false;
        }
        return true;
    }
}

11.linux文件上传报413 Payload Too Large

(1)在nginx中加入:client_max_body_size 200M;

在这里插入图片描述
参考:https://blog.csdn.net/weixin_43652507/article/details/122130540

12.自定义加载消息

submitForm() {
  this.$refs['elForm'].validate(valid => {
    if (!valid) return
    let ld = Loading.service({ text: "系统处理中,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
    update(this.formData).then(response => {
      ld.close()
      this.$modal.msgSuccess("修改成功");
    });
  })
}

13.登录单独设置token过期时间

(1)application.yml

# token配置
token:
  # 令牌自定义标识
  header: Authorization
  # 令牌密钥
  secret: abcdefghijklmnopqrstuvwxyz
  # 令牌有效期(默认30分钟)
  expireTime: 720
  # 前端令牌有效期 30天
  appExpireTime: 43200

(2)LoginUser.java

/**
* 类型(0.后端登录,1.前端登录)
*/
private Integer type=0;

public Integer getType() {
   return type;
}

public void setType(Integer type) {
   this.type = type;
}

(3)TokenService.java

/**
 * 刷新令牌有效期
 *
 * @param loginUser 登录信息
 */
public void refreshToken(LoginUser loginUser) {
    loginUser.setLoginTime(System.currentTimeMillis());
    int exTime = getExTime(loginUser.getType());

    loginUser.setExpireTime(loginUser.getLoginTime() + exTime * MILLIS_MINUTE);
    // 根据uuid将loginUser缓存
    String userKey = getTokenKey(loginUser.getToken());
    redisCache.setCacheObject(userKey, loginUser, exTime, TimeUnit.MINUTES);
}

/**
 * 过期时间获取
 *
 * @param type
 * @return
 */
private int getExTime(Integer type) {
    int exTime = 0;
    if (type == 0) {//后端
        exTime = expireTime;
    } else if (type == 1) {//前端
        exTime = appExpireTime;
    }
    return exTime;
}

(4)JwtAuthenticationTokenFilter 登录验证token拦截类

14.Name for argument of type [java.lang.String] not specified, and parameter name information not available via reflection. Ensure that the compiler uses the ‘-parameters’ flag.

解决办法
1.@RequestParam(name=“tables”)
在这里插入图片描述
参考:http://t.csdnimg.cn/gCIzN

15.偌依首页图片获取位置

在这里插入图片描述

16.数据监控密码

在这里插入图片描述

17. 打开一个新的页面

(1) 父页面

<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
  <el-table-column label="字典类型" align="left" :show-overflow-tooltip="true">
    <template slot-scope="scope">
      <router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
        <span>{{ scope.row.dictType }}</span>
      </router-link>
    </template>
  </el-table-column>
</el-table>

(2)router–》index.js

a.动态路由

{
  path: '/system/dict-data',
  component: Layout,
  hidden: true,
  permissions: ['system:dict:list'],
  children: [
    {
      path: 'index/:dictId(\\d+)',
      component: () => import('@/views/system/dict/data'),
      name: 'Data',
      meta: { title: '字典数据', activeMenu: '/system/dict' }
    }
  ]
},

b.静态路由

{
  path: '/mode2/boxPateItem',
  component: Layout,
  hidden: true,
  redirect: 'index',
  children: [
    {
      path: 'index/:boxPeriodId(\\d+)',
      component: () => import('@/views/mode2/boxPateItem/index'),
      name: 'boxPateItem',
      meta: { title: '参与物品', icon: 'boxPateItem' }
    }
  ]
},

(3)子页面

created() {
  const dictId = this.$route.params && this.$route.params.dictId;
  this.getTypeList();
},

18.数据字典sql自动生成

(1)输入类型编码和说明自动生成sql

public class Test {

    public static void main(String[] args) {
        String dict_type="product_order_status";
        String name_label_value="订单状态:0=未付款,1=已付款(待发货),2=已发货(待收货),3=已签收(已完成),4=退货申请,5=退货中,6=已退货,9=取消交易";
        createSql(name_label_value, dict_type);
    }

    private static void createSql(String name_label_value, String dict_type) {
        String dict_name= name_label_value.split(":|:")[0];
        String label_value= name_label_value.split(":|:")[1];

        String tableType="INSERT INTO sys_dict_type ( dict_name, dict_type, status, create_by, create_time) VALUES ('"+dict_name+"', '"+ dict_type +"', '0', 'admin', SYSDATE());";
        System.out.println(tableType);

        String[] arr = label_value.split(",|,");
        for  (int i = 0; i < arr.length; i++)  {
            String value=arr[i].split("=|\\.")[0];
            String label=arr[i].split("=|\\.")[1];
            String tableData="INSERT INTO sys_dict_data ( dict_sort, dict_label, dict_value, dict_type, list_class, create_by, create_time) VALUES ("+i+", '"+label+"', '"+value+"', '"+ dict_type +"', 'primary', 'admin', SYSDATE());";
            System.out.println(tableData);
        }
    }
}

(2)直接查询数据库生成

a.表格式

在这里插入图片描述

b.代码

package com.gu.web.controller;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;

public class Test {
    //数据库连接
    private static final String url="jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai";
    //数据库账号
    private static final String user="root";
    //数据库密码
    private static final String password="root";


    public static void main(String[] args) {
        //以下sql用于辅助快速查询数据库中的表
        //SELECT GROUP_CONCAT(table_name) FROM information_schema.`TABLES` WHERE table_name LIKE 't_%'

        String tables="t_product,t_product_order";
        createSql(tables,2);
    }

    /**
     * 获取数据字典插入sql
     * @param tables 表名,多个表用逗号分隔
     * @param type 类型(1.需要前缀,2.去掉前缀)
     */
    private static void createSql(String tables,int type) {
        for (String table : tables.split(",|,")) {
            System.out.println("-- "+table);
            Connection mysqlConn=null;
            Statement mysqlStmt=null;
            ResultSet mysqlRs=null;
            ResultSet resultSet=null;
            String tableComment="";
            String dt=table;
            if (type==2) {
                dt=table.substring(table.indexOf("_")+1);
            }

            try {
                Class.forName("com.mysql.cj.jdbc.Driver");
                mysqlConn= DriverManager.getConnection(url,user,password);
                mysqlStmt=mysqlConn.createStatement();
                mysqlRs=mysqlStmt.executeQuery("select * from "+ table);

                ResultSetMetaData mysqlMeda=mysqlRs.getMetaData();

                int columnCount=mysqlMeda.getColumnCount();

                //获取字段注释map
                DatabaseMetaData metaData = mysqlConn.getMetaData();
                Map<String, String> columnComments = getColumnComments(metaData, table);

                //获取表注释
                resultSet = mysqlStmt.executeQuery("Select TABLE_COMMENT COMMENT from INFORMATION_SCHEMA.TABLES Where table_name = '" + table + "'");
                while (resultSet.next()) {
                     tableComment = resultSet.getString("COMMENT");
                }

                for (int i = 1; i <= columnCount; i++) {
                    String columnName=mysqlMeda.getColumnName(i);//字段名
                    String columnComment = columnComments.get(columnName);//字段注释
                    if (columnComment.contains(":") || columnComment.contains(":")){
                        pjSql(columnComment,dt+"_"+columnName,tableComment);
                    }
                }
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            } finally {
                try {
                    if (mysqlConn!=null){
                        mysqlConn.close();
                    }
                    if (mysqlStmt!=null){
                        mysqlStmt.close();
                    }
                    if (mysqlRs!=null){
                        mysqlRs.close();
                    }
                    if (resultSet!=null){
                        resultSet.close();
                    }
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * sql组装
     * @param name_label_value 如:订单状态:0=未付款,1=已付款(待发货),2=已发货(待收货),3=已签收(已完成),4=退货申请,5=退货中,6=已退货,9=取消交易
     * @param dict_type 如:product_order_status
     */
    private static void pjSql(String name_label_value, String dict_type,String tableComment) {
        String dict_name= name_label_value.split(":|:")[0];
        String label_value= name_label_value.split(":|:")[1];

        String tableType="INSERT INTO sys_dict_type ( dict_name, dict_type, status, create_by, create_time) VALUES ('"+tableComment+"-"+dict_name+"', '"+ dict_type +"', '0', 'admin', SYSDATE());";
        System.out.println(tableType);

        String[] arr = label_value.split(",|,");
        for  (int i = 0; i < arr.length; i++)  {
            String value=arr[i].split("=|\\.")[0];
            String label=arr[i].split("=|\\.")[1];
            String tableData="INSERT INTO sys_dict_data ( dict_sort, dict_label, dict_value, dict_type, list_class, create_by, create_time) VALUES ("+i+", '"+label+"', '"+value+"', '"+ dict_type +"', 'primary', 'admin', SYSDATE());";
            System.out.println(tableData);
        }
        System.out.println();
    }


    /**获取字段注注释*/
    private static Map<String, String> getColumnComments(DatabaseMetaData metaData, String tableName) throws SQLException {
        Map<String, String> columnComments = new HashMap<>();
        try (ResultSet columns = metaData.getColumns(null, null, tableName, null)) {
            while (columns.next()) {
                String columnName = columns.getString("column_name");
                String columnComment = columns.getString("remarks");
                columnComments.put(columnName, columnComment);
            }
        }
        return columnComments;
    }
}


19.菜单目录去掉井号可以向前移动

在这里插入图片描述
在这里插入图片描述

20.vue项目idea提示Module is not installed

参考:http://t.csdnimg.cn/Lgmod

在这里插入图片描述

21.增加多张图片写法

(1)前端

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2)后端

在这里插入图片描述

22.ruoyi的springboot微信小程序登录实现方式

ruoyi的springboot微信小程序登录实现方式

23.代码生成器自动插入数据字典实现

(1)表设计(新增数据字典)

在这里插入图片描述

(2)表设计(公共:从已有的数据字典获取)

在这里插入图片描述

(2)导入的时候插入数据字典

在这里插入图片描述

(3)数据字典效果

在这里插入图片描述
在这里插入图片描述

(4)代码实现

表gen_table_column增加字段table_name
在这里插入图片描述

导入:/tool/gen/importTable
在这里插入图片描述
在这里插入图片描述

删除:/tool/gen/{{tableIds}}
在这里插入图片描述
在这里插入图片描述

24.代码生成器自动生成枚举

(1)预览 /tool/gen/preview/{tableId}

在这里插入图片描述

(2)代码生成 /tool/gen/batchGenCode

在这里插入图片描述

25.代码生成器模板语法记录

(1)定义变量用法

  • 定义:#set($Entity=“TreeEntity”)
  • 使用:${Entity}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ruoyi框架中,可以使用RabbitMQ作为消息队列服务。RabbitMQ在消息的发送、传输和接收过程中,可以保证消息成功发送不会丢失,并且能够确认被消费。它提供了消息的高可用性和消费确认功能。 然而,在实际应用中,如果配置和使用不当,可能会遇到一些问题。例如,发送出去的消息可能未能成功到达目的地,这可能是由于消息模型不存在的原因导致的(比如交换机、路由和队列绑定结构错误)。此外,如果RabbitMQ服务发生宕机或崩溃,还可能导致未被消费的消息在重启过程中丢失。另外,消费者在监听和处理消息时可能会出现失败或崩溃的情况,导致消息重新入队并被重复消费的问题。 在Ruoyi中,可以使用RabbitReceiverService类来监听订单消息。这个类使用@RabbitListener注解来指定监听的队列,并在方法中处理接收到的消息。在具体的实现中,可以根据消息的内容执行相应的业务逻辑。例如,在监听到用户秒杀成功后超时未支付的消息时,可以根据消息中的信息更新数据库中的订单状态。 总结来说,Ruoyi框架可以使用RabbitMQ作为消息队列服务,并通过监听器来接收和处理消息。这个功能可以用于实现一些异步处理或解耦的需求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Spring Boot 整合RabbitMQ](https://blog.csdn.net/qq_38828776/article/details/103971951)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [RabbitMQ死信队列处理超时未支付的订单](https://blog.csdn.net/weixin_38982591/article/details/111404721)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值