Files
yidaima/RuoYi-Vue/docs/superpowers/plans/2026-07-06-real-image-seed-data.md

26 KiB

Real Image Seed Data Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Generated sample SQL stores image URLs that point to real bundled image files in generated runnable projects.

Architecture: Keep database values as web resource URLs, not server disk paths. Add one small Java support class that owns deterministic mock image URLs, generated PNG bytes, and generated asset paths. Use that support class from SQL seed generation and from backend ZIP packaging, then update the generated file controller so /files/mock/image-01.png can be served safely.

Tech Stack: Java 8, Spring Boot generated templates, Velocity templates, ZIP packaging, JUnit 4, Mockito, MySQL seed SQL files.


File Structure

  • Create: ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockImageSeedSupport.java
    • Owns /files/mock/image-XX.png URLs and generated uploads/mock/image-XX.png PNG bytes.
  • Create: ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/MockImageSeedSupportTest.java
    • Verifies generated images are readable PNGs and URL/path numbering is stable.
  • Modify: ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockDataSqlBuilder.java
    • Replaces hard-coded /files/mock/image-N.png values with MockImageSeedSupport.imageUrlForRow(row).
  • Modify: ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/MockDataSqlBuilderTest.java
    • Covers image seed URL output.
  • Modify: ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenProjectServiceImpl.java
    • Adds bundled mock images to backend ZIP output beside the generated backend pom.xml.
  • Modify: ruoyi-generator/src/test/java/com/ruoyi/generator/service/GenProjectServiceImplTest.java
    • Covers backend ZIP entries for uploads/mock/image-01.png and uploads/mock/image-10.png.
  • Modify: ruoyi-generator/src/main/resources/qing/fileController.java.vm
    • Serves nested paths under /files/** and blocks path traversal.
  • Modify: ruoyi-generator/src/test/java/com/ruoyi/generator/util/QingTemplateSupportTest.java
    • Covers the file controller template and SQL seed copies.
  • Modify: sql/qing_templates.sql
    • Syncs the FileController.java.vm template seed.
  • Modify: sql/db.sql
    • Syncs the runnable template seed copy.

Task 1: Add Mock Image Seed Support

Files:

  • Create: ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockImageSeedSupport.java

  • Create: ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/MockImageSeedSupportTest.java

  • Step 1: Write the failing tests

Create ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/MockImageSeedSupportTest.java:

package com.ruoyi.generator.service.front;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import javax.imageio.ImageIO;
import org.junit.Test;

public class MockImageSeedSupportTest
{
    @Test
    public void imageUrlsAndAssetPathsUseStableTwoDigitNames()
    {
        assertEquals("/files/mock/image-01.png", MockImageSeedSupport.imageUrlForRow(1));
        assertEquals("/files/mock/image-10.png", MockImageSeedSupport.imageUrlForRow(10));
        assertEquals("/files/mock/image-01.png", MockImageSeedSupport.imageUrlForRow(11));
        assertEquals("uploads/mock/image-01.png", MockImageSeedSupport.imageAssetPathForRow(1));
        assertEquals("uploads/mock/image-10.png", MockImageSeedSupport.imageAssetPathForRow(10));
    }

    @Test
    public void createsReadablePngImagesForAllSeedRows() throws Exception
    {
        for (int row = 1; row <= MockImageSeedSupport.IMAGE_COUNT; row++)
        {
            byte[] bytes = MockImageSeedSupport.imageBytesForRow(row);

            assertTrue("image bytes should not be empty", bytes.length > 1000);
            BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));
            assertNotNull("image should be readable", image);
            assertEquals(640, image.getWidth());
            assertEquals(360, image.getHeight());
        }
    }
}
  • Step 2: Run tests to verify failure

Run:

mvn -q -pl ruoyi-generator -Dtest=MockImageSeedSupportTest test

Expected: FAIL because MockImageSeedSupport does not exist.

  • Step 3: Add the support class

Create ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockImageSeedSupport.java:

package com.ruoyi.generator.service.front;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Locale;
import javax.imageio.ImageIO;

public final class MockImageSeedSupport
{
    public static final int IMAGE_COUNT = 10;
    private static final int WIDTH = 640;
    private static final int HEIGHT = 360;
    private static final Color[] BACKGROUNDS = new Color[] {
            new Color(44, 123, 229),
            new Color(0, 150, 136),
            new Color(255, 152, 0),
            new Color(103, 58, 183),
            new Color(76, 175, 80),
            new Color(233, 30, 99),
            new Color(63, 81, 181),
            new Color(0, 121, 107),
            new Color(198, 40, 40),
            new Color(69, 90, 100)
    };

    private MockImageSeedSupport()
    {
    }

    public static String imageUrlForRow(int row)
    {
        return "/files/mock/image-" + imageNumber(row) + ".png";
    }

    public static String imageAssetPathForRow(int row)
    {
        return "uploads/mock/image-" + imageNumber(row) + ".png";
    }

    public static byte[] imageBytesForRow(int row) throws IOException
    {
        int index = normalizedIndex(row);
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = image.createGraphics();
        try
        {
            drawImage(graphics, index);
        }
        finally
        {
            graphics.dispose();
        }
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ImageIO.write(image, "png", output);
        return output.toByteArray();
    }

    private static void drawImage(Graphics2D graphics, int index)
    {
        Color background = BACKGROUNDS[index - 1];
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics.setColor(background);
        graphics.fillRect(0, 0, WIDTH, HEIGHT);

        graphics.setColor(new Color(255, 255, 255, 42));
        graphics.fillOval(-90, -80, 260, 260);
        graphics.fillOval(WIDTH - 210, HEIGHT - 180, 300, 300);

        graphics.setStroke(new BasicStroke(3f));
        graphics.setColor(new Color(255, 255, 255, 80));
        graphics.drawRoundRect(28, 28, WIDTH - 56, HEIGHT - 56, 28, 28);

        drawCenteredText(graphics, "Sample Image", new Font(Font.SANS_SERIF, Font.BOLD, 42), HEIGHT / 2 - 22);
        drawCenteredText(graphics, imageNumber(index), new Font(Font.SANS_SERIF, Font.BOLD, 72), HEIGHT / 2 + 62);
    }

    private static void drawCenteredText(Graphics2D graphics, String text, Font font, int baseline)
    {
        graphics.setFont(font);
        FontMetrics metrics = graphics.getFontMetrics();
        int x = (WIDTH - metrics.stringWidth(text)) / 2;
        graphics.setColor(Color.WHITE);
        graphics.drawString(text, x, baseline);
    }

    private static String imageNumber(int row)
    {
        return String.format(Locale.ENGLISH, "%02d", normalizedIndex(row));
    }

    private static int normalizedIndex(int row)
    {
        int safeRow = Math.max(1, row);
        return ((safeRow - 1) % IMAGE_COUNT) + 1;
    }
}
  • Step 4: Run tests to verify pass

Run:

mvn -q -pl ruoyi-generator -Dtest=MockImageSeedSupportTest test

Expected: PASS.

  • Step 5: Commit
git add ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockImageSeedSupport.java ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/MockImageSeedSupportTest.java
git commit -m "feat: add bundled mock image seed support"

Task 2: Use Real Image URLs in Mock SQL

Files:

  • Modify: ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/MockDataSqlBuilderTest.java

  • Modify: ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockDataSqlBuilder.java

  • Step 1: Write the failing test

Add this test method to MockDataSqlBuilderTest:

    @Test
    public void imageUploadColumnsUseBundledMockImageUrls()
    {
        DatabaseTableDesign table = new DatabaseTableDesign();
        table.setTableName("product");
        table.setColumns(Arrays.asList(
                column("id", "bigint(20)", "ID", "ID", "1", "1", "input", null, null),
                column("cover_url", "varchar(100)", "Cover", "Cover", "0", "0", "imageUpload", null, null),
                column("avatar_url", "varchar(100)", "Avatar", "Avatar", "0", "0", "avatar", null, null)));

        String sql = builder.build(table);

        assertTrue(sql.contains("'/files/mock/image-01.png' as `cover_url`"));
        assertTrue(sql.contains("'/files/mock/image-01.png' as `avatar_url`"));
        assertTrue(sql.contains("'/files/mock/image-10.png'"));
        assertFalse(sql.contains("/files/mock/image-1.png"));
    }
  • Step 2: Run test to verify failure

Run:

mvn -q -pl ruoyi-generator -Dtest=MockDataSqlBuilderTest#imageUploadColumnsUseBundledMockImageUrls test

Expected: FAIL because the existing SQL contains /files/mock/image-1.png.

  • Step 3: Replace the image branch

In MockDataSqlBuilder.valueFor, replace this branch:

        if (StringUtils.inStringIgnoreCase(htmlType, "imageUpload", "avatar"))
        {
            return quoted(fitTextValue("/files/mock/image-" + row + ".png", column));
        }

with:

        if (StringUtils.inStringIgnoreCase(htmlType, "imageUpload", "avatar"))
        {
            return quoted(fitTextValue(MockImageSeedSupport.imageUrlForRow(row), column));
        }

No import is needed because both classes are in com.ruoyi.generator.service.front.

  • Step 4: Run tests to verify pass

Run:

mvn -q -pl ruoyi-generator -Dtest=MockDataSqlBuilderTest,MockImageSeedSupportTest test

Expected: PASS.

  • Step 5: Commit
git add ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockDataSqlBuilder.java ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/MockDataSqlBuilderTest.java
git commit -m "feat: seed image columns with bundled file urls"

Task 3: Package Mock Images into Backend Downloads

Files:

  • Modify: ruoyi-generator/src/test/java/com/ruoyi/generator/service/GenProjectServiceImplTest.java

  • Modify: ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenProjectServiceImpl.java

  • Step 1: Write the failing ZIP test

Add this test method near the existing downloadStructure... tests in GenProjectServiceImplTest:

    @Test
    public void downloadStructurePackagesMockImageAssetsWithBackend() throws Exception {
        GenProject project = project();
        project.setFrontDraft(true);

        TemplateFile pomTemplate = templateFile("pom.xml.vm", "<project></project>");
        pomTemplate.setTemplateId(9201L);

        when(templateService.selectTemplateList(any(Template.class))).thenReturn(Arrays.asList(template(9201L, 0L)));
        when(sysProjectStructureService.selectSysProjectStructureList(any(SysProjectStructure.class))).thenReturn(Arrays.asList(
                structure(1L, 0L, "{projectName}", "folder", null, null),
                structure(2L, 1L, "pom.xml", "file", 11L, "pom.xml.vm")
        ));
        when(sysProjectModuleService.selectSysProjectModuleList(any(SysProjectModule.class))).thenReturn(Arrays.asList());
        when(codeSnippetService.selectSysCodeSnippetList(any(SysCodeSnippet.class))).thenReturn(Arrays.asList());
        when(templateFileService.selectTemplateFilesByTemplateId(9201L)).thenReturn(Arrays.asList(pomTemplate));

        byte[] data = service.downloadStructure(project, "backend");

        Set<String> entries = zipEntries(data);
        assertTrue(entries.contains("demo-app/uploads/mock/image-01.png"));
        assertTrue(entries.contains("demo-app/uploads/mock/image-10.png"));
    }
  • Step 2: Run test to verify failure

Run:

mvn -q -pl ruoyi-generator -Dtest=GenProjectServiceImplTest#downloadStructurePackagesMockImageAssetsWithBackend test

Expected: FAIL because backend ZIPs do not include uploads/mock/image-01.png.

  • Step 3: Add import

In GenProjectServiceImpl.java, add:

import com.ruoyi.generator.service.front.MockImageSeedSupport;
  • Step 4: Replace processStructure and add helpers

Replace the existing processStructure method:

    private void processStructure(List<Map<String, Object>> structure, ZipOutputStream zip, GenProject project, String type) throws IOException {
        processStructureWithPath(structure, zip, project, "", type, new HashSet<String>());
    }

with:

    private void processStructure(List<Map<String, Object>> structure, ZipOutputStream zip, GenProject project, String type) throws IOException {
        Set<String> zipEntries = new HashSet<String>();
        processStructureWithPath(structure, zip, project, "", type, zipEntries);
        appendMockImageAssets(zip, type, zipEntries);
    }

    private void appendMockImageAssets(ZipOutputStream zip, String type, Set<String> zipEntries) throws IOException {
        if (!"backend".equals(type)) {
            return;
        }
        String backendRootPrefix = backendRootPrefix(zipEntries);
        if (backendRootPrefix == null) {
            return;
        }
        for (int row = 1; row <= MockImageSeedSupport.IMAGE_COUNT; row++) {
            String entryName = backendRootPrefix + MockImageSeedSupport.imageAssetPathForRow(row);
            if (zipEntries.add(entryName)) {
                zip.putNextEntry(new ZipEntry(entryName));
                zip.write(MockImageSeedSupport.imageBytesForRow(row));
                zip.closeEntry();
            }
        }
    }

    private String backendRootPrefix(Set<String> zipEntries) {
        for (String entryName : zipEntries) {
            if ("pom.xml".equals(entryName)) {
                return "";
            }
            if (entryName != null && entryName.endsWith("/pom.xml")) {
                return entryName.substring(0, entryName.length() - "pom.xml".length());
            }
        }
        return null;
    }
  • Step 5: Run focused tests

Run:

mvn -q -pl ruoyi-generator -Dtest=GenProjectServiceImplTest#downloadStructurePackagesMockImageAssetsWithBackend,MockImageSeedSupportTest test

Expected: PASS.

  • Step 6: Commit
git add ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenProjectServiceImpl.java ruoyi-generator/src/test/java/com/ruoyi/generator/service/GenProjectServiceImplTest.java
git commit -m "feat: package mock images with generated backend"

Task 4: Serve Nested Mock Image Paths

Files:

  • Modify: ruoyi-generator/src/main/resources/qing/fileController.java.vm

  • Modify: ruoyi-generator/src/test/java/com/ruoyi/generator/util/QingTemplateSupportTest.java

  • Step 1: Write the failing template test

In QingTemplateSupportTest, add this test method near the other runnable Qing template checks:

    @Test
    public void fileControllerTemplateServesNestedMockImagePathsSafely() throws Exception
    {
        String template = read(repoRoot().resolve("ruoyi-generator/src/main/resources/qing/fileController.java.vm"));

        assertTrue(template.contains("@GetMapping(\"/**\")"));
        assertTrue(template.contains("HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE"));
        assertTrue(template.contains("Path normalizedRoot = uploadRoot.toAbsolutePath().normalize();"));
        assertTrue(template.contains("if (!filePath.startsWith(normalizedRoot))"));
        assertFalse(template.contains("@GetMapping(\"/{fileName:.+}\")"));
    }
  • Step 2: Run test to verify failure

Run:

mvn -q -pl ruoyi-generator -Dtest=QingTemplateSupportTest#fileControllerTemplateServesNestedMockImagePathsSafely test

Expected: FAIL because the template still uses @GetMapping("/{fileName:.+}").

  • Step 3: Replace the file controller template content

Replace the complete content of ruoyi-generator/src/main/resources/qing/fileController.java.vm with:

package ${packageName}.controller;

import ${packageName}.common.Result;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

@RestController
@RequestMapping("/files")
public class FileController
{
    private final Path uploadRoot = Paths.get("uploads");

    @PostMapping("/upload")
    public Result<Map<String, String>> upload(@RequestParam("file") MultipartFile file) throws IOException
    {
        Files.createDirectories(uploadRoot);
        String originalName = StringUtils.cleanPath(file.getOriginalFilename() == null ? "file" : file.getOriginalFilename());
        String suffix = "";
        int dotIndex = originalName.lastIndexOf('.');
        if (dotIndex >= 0)
        {
            suffix = originalName.substring(dotIndex);
        }
        String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;
        Files.copy(file.getInputStream(), uploadRoot.resolve(fileName), StandardCopyOption.REPLACE_EXISTING);

        Map<String, String> data = new HashMap<String, String>();
        data.put("name", originalName);
        data.put("url", "/files/" + fileName);
        return Result.success(data);
    }

    @GetMapping("/**")
    public ResponseEntity<Resource> getFile(HttpServletRequest request) throws MalformedURLException
    {
        String requestPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        String fileName = cleanStoredPath(requestPath);
        if (!StringUtils.hasText(fileName))
        {
            return ResponseEntity.notFound().build();
        }

        Path normalizedRoot = uploadRoot.toAbsolutePath().normalize();
        Path filePath = normalizedRoot.resolve(fileName).normalize();
        if (!filePath.startsWith(normalizedRoot))
        {
            return ResponseEntity.notFound().build();
        }

        Resource resource = new UrlResource(filePath.toUri());
        if (!resource.exists())
        {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }

    private String cleanStoredPath(String requestPath)
    {
        String storedPath = requestPath == null ? "" : requestPath;
        if (storedPath.startsWith("/files/"))
        {
            storedPath = storedPath.substring("/files/".length());
        }
        else if (storedPath.startsWith("/files"))
        {
            storedPath = storedPath.substring("/files".length());
        }
        while (storedPath.startsWith("/"))
        {
            storedPath = storedPath.substring(1);
        }
        storedPath = StringUtils.cleanPath(storedPath);
        return storedPath.contains("..") ? "" : storedPath;
    }
}
  • Step 4: Run template test

Run:

mvn -q -pl ruoyi-generator -Dtest=QingTemplateSupportTest#fileControllerTemplateServesNestedMockImagePathsSafely test

Expected: PASS.

  • Step 5: Commit
git add ruoyi-generator/src/main/resources/qing/fileController.java.vm ruoyi-generator/src/test/java/com/ruoyi/generator/util/QingTemplateSupportTest.java
git commit -m "fix: serve generated mock image subpaths"

Task 5: Sync SQL Template Seeds

Files:

  • Modify: sql/qing_templates.sql

  • Modify: sql/db.sql

  • Modify: ruoyi-generator/src/test/java/com/ruoyi/generator/util/QingTemplateSupportTest.java

  • Step 1: Add SQL seed assertions

In QingTemplateSupportTest, add this test method:

    @Test
    public void sqlSeedFileControllerTemplatesServeNestedMockImagePaths() throws Exception
    {
        String qingTemplatesSql = read(repoRoot().resolve("sql/qing_templates.sql"));
        String dbSql = read(repoRoot().resolve("sql/db.sql"));

        assertTrue(qingTemplatesSql.contains("'FileController.java.vm'"));
        assertTrue(qingTemplatesSql.contains("@GetMapping(\"/**\")"));
        assertTrue(qingTemplatesSql.contains("HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE"));
        assertTrue(qingTemplatesSql.contains("if (!filePath.startsWith(normalizedRoot))"));
        assertFalse(qingTemplatesSql.contains("@GetMapping(\"/{fileName:.+}\")"));

        assertTrue(dbSql.contains("'FileController.java.vm'"));
        assertTrue(dbSql.contains("@GetMapping(\"/**\")"));
        assertTrue(dbSql.contains("HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE"));
        assertTrue(dbSql.contains("if (!filePath.startsWith(normalizedRoot))"));
        assertFalse(dbSql.contains("@GetMapping(\"/{fileName:.+}\")"));
    }
  • Step 2: Run test to verify failure

Run:

mvn -q -pl ruoyi-generator -Dtest=QingTemplateSupportTest#sqlSeedFileControllerTemplatesServeNestedMockImagePaths test

Expected: FAIL because sql/qing_templates.sql and sql/db.sql still contain the old file controller template.

  • Step 3: Mechanically sync the SQL template body

Run this PowerShell command from the repository root:

$templatePath = "ruoyi-generator/src/main/resources/qing/fileController.java.vm"
$template = Get-Content -Raw -Encoding UTF8 $templatePath
$escaped = $template.Replace("\", "\\").Replace("'", "''")
foreach ($path in @("sql/qing_templates.sql", "sql/db.sql")) {
  $text = Get-Content -Raw -Encoding UTF8 $path
  $marker = "(920107, 9201, 'FileController.java.vm', NULL, 'FileController.java.vm', '"
  $start = $text.IndexOf($marker)
  if ($start -lt 0) { throw "FileController template row not found in $path" }
  $contentStart = $start + $marker.Length
  $contentEnd = $text.IndexOf("`n', 'admin', sysdate())", $contentStart)
  if ($contentEnd -lt 0) { throw "FileController template row end not found in $path" }
  $updated = $text.Substring(0, $contentStart) + $escaped + $text.Substring($contentEnd)
  Set-Content -Path $path -Value $updated -Encoding UTF8
}
  • Step 4: Run SQL seed test

Run:

mvn -q -pl ruoyi-generator -Dtest=QingTemplateSupportTest#sqlSeedFileControllerTemplatesServeNestedMockImagePaths test

Expected: PASS.

  • Step 5: Commit
git add sql/qing_templates.sql sql/db.sql ruoyi-generator/src/test/java/com/ruoyi/generator/util/QingTemplateSupportTest.java
git commit -m "chore: sync runnable file controller template seeds"

Task 6: Final Verification

Files:

  • Verify only, no file edits.

  • Step 1: Run focused Java tests

Run:

mvn -q -pl ruoyi-generator -Dtest=MockImageSeedSupportTest,MockDataSqlBuilderTest,GenProjectServiceImplTest,QingTemplateSupportTest test

Expected: PASS.

  • Step 2: Verify generated SQL values

Run:

rg -n "/files/mock/image-0[1-9]\\.png|/files/mock/image-10\\.png|/files/mock/image-[1-9]\\.png" ruoyi-generator/src/main/java ruoyi-generator/src/test/java

Expected: output includes the new two-digit paths in tests or assertions, and no production Java code contains /files/mock/image- followed by a single digit.

  • Step 3: Verify SQL seed copies

Run:

rg -n "HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE|@GetMapping\\(\"/\\*\\*\"\\)|@GetMapping\\(\"/\\{fileName:\\.\\+\\}\"\\)" ruoyi-generator/src/main/resources/qing/fileController.java.vm sql/qing_templates.sql sql/db.sql

Expected: output includes HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE and @GetMapping("/**"); output does not include @GetMapping("/{fileName:.+}").

  • Step 4: Verify ZIP contents with the focused test already exercising bytes

Run:

mvn -q -pl ruoyi-generator -Dtest=GenProjectServiceImplTest#downloadStructurePackagesMockImageAssetsWithBackend test

Expected: PASS, proving backend downloads include demo-app/uploads/mock/image-01.png and demo-app/uploads/mock/image-10.png.

  • Step 5: Check whitespace

Run:

git diff --check

Expected: no output.

  • Step 6: Review final diff

Run:

git diff --stat
git diff -- ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockImageSeedSupport.java ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/MockDataSqlBuilder.java ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenProjectServiceImpl.java ruoyi-generator/src/main/resources/qing/fileController.java.vm

Expected: diff is limited to mock image support, image seed SQL path selection, backend ZIP asset packaging, nested file serving, tests, and SQL template seed copies.


Self-Review

  • Spec coverage: sample image columns store /files/mock/image-XX.png; generated backend ZIPs contain matching uploads/mock/image-XX.png files; generated file controller serves nested mock/... resource paths; SQL template seed copies are synchronized.
  • Placeholder scan: all code-producing steps include concrete code or concrete replacement snippets.
  • Type consistency: MockImageSeedSupport.imageUrlForRow, imageAssetPathForRow, imageBytesForRow, and IMAGE_COUNT are used consistently across SQL builder, ZIP packaging, and tests.