Tạo và Quản Lý Mô-đun Trong Hệ Thống RuoYi

Hệ thống mục tiêu: Phiên bản phân tách của RuoYi 3.8.5, phiên bản không phân tách của RuoYi 4.5.0

Tạo mô-đun riêng biệt với mã nguồn của RuoYi

Tạo một mô-đun mới trong dự án gốc, ví dụ gọi là quanly, nhóm tên là com.ruoyi, tên công cụ là quanly. Lưu ý đặc biệt: Khi sử dụng chức năng sinh mã, hãy dùng tên hoàn toàn viết thường và dạng camelCase, không thêm các ký tự như - để tránh lỗi.

Kết cấu thư mục sau khi tạo như sau:

Chỉnh sửa file pom.xml của mô-đun quanly, thêm phụ thuộc ruoyi-framework

<!-- Thêm phụ thuộc vào pom.xml của mô-đun mới -->
    <dependencies>
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-framework</artifactId>
        </dependency>
    </dependencies>

Thêm phụ thuộc của mô-đun quanly vào ruoyi-admin

Kiểm tra xem trong phần modules của file pom.xml ở dự án gốc ruoyi đã thêm đúng mô-đun mới (bao gồm cả việc loại bỏ các mô-đun không tồn tại) chưa.

Quản lý menu và xung đột khi sinh mã

Quản lý menu có thể tạo và quản lý menu và thành phần nút mà không cần lập trình, nhưng trong một số trường hợp có thể xung đột với chức năng sinh mã: Tạo thư mục A, dưới thư mục A tạo menu A1, khi tạo menu sẽ yêu cầu bạn điền địa chỉ route, đường dẫn component, ký tự quyền hạn, tham số route, v.v. Nếu không hiểu rõ tác động sau khi điền, nên thử điền và tạo menu. Sau đó trong phần thông tin sinh mã có thể chọn menu cấp trên, đây chính là điểm xung đột. Nếu chọn thư mục A, sẽ tạo ra hai menu A1 dưới thư mục A, nếu chọn menu A1, sẽ tạo ra menu A1 khác bên dưới menu A1 (tạo bởi quản lý menu). Phân tích cho thấy cách sử dụng có thể không đúng, hai chức năng này có lẽ nên bổ sung và hỗ trợ lẫn nhau.

Cải tiến cách sử dụng như sau: Ý tưởng chính là sử dụng chức năng quản lý menu để tạo các menu đơn giản như thư mục mà không có logic yêu cầu phía backend. Nếu menu cấp dưới cũng không có logic yêu cầu thì cũng có thể làm tương tự. Sau đó sử dụng chức năng sinh mã để tạo mã frontend và backend, trong quá trình sinh mã chọn menu cấp trên trong phần thông tin sinh mã để liên kết mã được sinh với menu. Ví dụ:

Tạo thư mục Quản Lý Doanh Nghiệp

Sinh mã tương ứng

Cấu trúc mã được sinh

Đối với mã frontend được sinh, mối quan hệ tương ứng vừa điền như sau

Đối với mã backend được sinh, mối quan hệ tương ứng vừa điền như sau

Sử dụng mã được sinh: Giải nén ruoyi.zip, chạy tập lệnh SQL được sinh, đặt các tệp trong thư mục vue vào thư mục src phía frontend, đặt các tệp trong thư mục main vào mô-đun Java đã tạo. Khởi động lại dự án frontend và backend lần lượt (nếu có sự cố, có thể thử tắt Idea, rebuild, khởi động lại máy tính) để xem hiệu quả.

Xếp hạng truy vấn (phiên bản phân tách)

Việc kiểm soát xếp hạng từ phía frontend khá linh hoạt và dễ dàng thực hiện, các logic liên quan đã được đóng gói trong framework RuoYi, phía backend nếu muốn lười có thể không cần biết gì, việc điều khiển từ phía frontend như sau

Chỉ định tham số, chỉ cần cung cấp các tham số đã thỏa thuận trong tham số truy vấn, orderByColumn chỉ định tên trường được sử dụng để sắp xếp, isAsc chỉ định quy tắc sắp xếp, ví dụ:

queryParams: {
pageNum: 1,
pageSize: 10,
orderByColumn: 'id',
isAsc: 'desc'
}

Framework RuoYi nhận diện hai tham số này, khi nhận được tham số truy vấn ở phía backend sẽ tự động thực hiện truy vấn theo yêu cầu và trả về kết quả, nhà phát triển backend không cần viết thêm mã.

Kiểm soát thành phần bảng, phiên bản phân tách của RuoYi mặc định sử dụng thành phần element-ui, thành phần bảng table cung cấp nhiều API, tài liệu chính thức có mô tả chi tiết về việc sử dụng sắp xếp, ở đây chỉ ghi lại phần quan trọng nhất. Thành phần table có hai khả năng sắp xếp, một là không cần tham gia từ phía backend, chỉ sắp xếp dữ liệu đã có ở phía frontend, để đạt được hiệu quả này chỉ cần thiết lập sortable cho cột, cột này sẽ xuất hiện mũi tên lên/xuống, khi nhấp vào cột, thứ tự hiển thị dữ liệu sẽ thay đổi.

<el-table-column label="Mã" align="center" sortable prop="id"/>

Thứ hai, yêu cầu thực sự sắp xếp từ phía backend, trước tiên thay đổi sortable thành sortable=custom, sau đó thêm sự kiện sort-change cho thành phần table, trong hàm callback của sự kiện này gửi yêu cầu đến backend để thực hiện "sắp xếp thật".

<el-table @sort-change="handleSortChange">
<el-table-column label="Mã" align="center" sortable="custom" prop="id"/>
</el-table>
...
methods: {
   // options.prop: Thuộc tính prop của cột gây ra sự kiện sắp xếp
   // options.order: Thứ tự sắp xếp, null-mặc định/không tăng không giảm/chưa bật bất kỳ mũi tên nào, ascending-tăng dần/mũi tên lên, descending-giảm dần/mũi tên xuống
   handleSortChange(options){
      // Gửi yêu cầu đến backend
   }
}

Cấu hình đa nguồn dữ liệu

Trước hết, thêm cấu hình nguồn dữ liệu vào file cấu hình 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

Trong file ruoyi-common\enums\DataSourceType thêm khai báo enum tương ứng

public enum DataSourceType{
 MASTER,
 SLAVEBI
}

Trong file ruoyi-framework\config\properties\DruidConfig thêm phương thức tương ứng

    @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);
    }
	
	 /**
     * Thiết lập nguồn dữ liệu
     * 
     * @param targetDataSources Tập hợp các nguồn dữ liệu tùy chọn
     * @param sourceName Tên nguồn dữ liệu
     * @param beanName Tên 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)
        {
        }
    }

Sử dụng chú thích @DataSource trên Service, Mapper hoặc phương thức để chuyển đổi nguồn dữ liệu

/**
 * Interface Mapper liên quan đến SmartBI
 * @author
 */
@Repository
@DataSource(value = DataSourceType.SLAVEBI)
public interface ContractSmartBIMapper {
    /**
     * Truy vấn thông tin ngân sách liên quan đến đơn đặt hàng mua sắm từ SmartBI
     * @param purchaseOrderDocNo Số hợp đồng (đơn đặt hàng mua sắm)
     * @return
     */
    public List<ContractBudgetBo> selectContractBudgetBoList(String purchaseOrderDocNo);
}

Tùy chỉnh bộ chặn

Bộ chặn trong Spring Boot

Đầu tiên, tạo lớp tùy chỉnh thực hiện HandlerInterceptor, trong phương thức addInterceptors của lớp triển khai WebMvcConfigurer thêm thể hiện của lớp chặn tùy chỉnh

package com.ruoyi.framework.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * Bộ chặn tùy chỉnh
 */
@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("Gọi phương thức Controller trước");

        if(handler instanceof HandlerMethod){
            System.out.println("CustomInterceptor preHandle: thực hiện 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("Thực hiện trước khi render trang sau khi gọi phương thức Controller");
    }
    
    @Override
    public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Thực hiện sau khi render trang sau khi gọi phương thức Controller");
    }
}

Cấu hình bộ chặn

@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("/**");
    }
}

Hiệu quả đầu ra trên console

Thẻ: ruoyi SpringBoot Java vuejs

Đăng vào ngày 11 tháng 7 lúc 12:40