跪拜 Guibai
← Back to the summary

A Frontend Dev's First Map of a Spring Boot Project

01 | Where Should a Frontend Developer Look First When Opening a Spring Boot Project?

This is the first article in the "Frontend Engineer Transitioning to Backend" series. The goal is not to immediately have you write complex business logic, but first to let you know: where this backend project starts, where an HTTP request comes in, and why the code is divided into layers like contract, service, Controller, Facade, DbService, Mapper, Entity, and SQL. When you later learn Java, MySQL, MyBatis-Plus, JWT, Redis, and order transactions, you will return to this project map for orientation.

Note: The Vue / Axios / TypeScript code appearing in this article are all "frontend-side illustrative code" used to help you migrate from frontend experience to backend understanding. The current repository does not have a real frontend source code directory. All backend paths in this article are based on the real files in the current repository.

Background: Why Frontend Developers Now Need to Understand Backend

Let's first talk about some real changes in work. Previously, many teams clearly divided roles: frontend only wrote pages, interactions, components, and API calls; backend only wrote APIs, databases, caches, and permissions. When frontend colleagues encountered API errors, they would throw a Network screenshot to the backend; after the backend colleagues modified the API, they would tell the frontend that fields, paths, and status codes had changed. This model can still work, but in many companies and business lines today, the boundaries are no longer so rigid.

Especially in small and medium-sized teams, startup teams, internal systems, admin panels, AI applications, low-code platforms, growth campaigns, and B-side businesses, bosses or business stakeholders often don't care "are you frontend or backend"; they only care when this requirement can go live: pages must exist, APIs must work, data must be stored, permissions must not be chaotic, and someone must be able to troubleshoot when online issues arise. Therefore, frontend colleagues often encounter these scenarios:

So this series of articles is not intended to "transform you from a frontend into a pure backend developer," but to help you supplement a backend perspective. You already know frontend, which is actually an advantage: you know how users operate pages, how APIs are called, what information in the browser Network tab is useful, and the importance of TypeScript types and API contracts. What you need to do next is to migrate this experience to the server side: understand the other end of axios.get(), and understand the DTOs, Services, database tables, caches, and permissions behind JSON fields.

You can understand this learning as an upgrade "from API caller to API provider." Previously, you mostly stood in the browser asking: "How do I use this API?" Now you need to start standing on the server side asking: "How should this API be designed? Where does the data come from? How to return on failure? Will there be errors under concurrency? How to avoid trapping the frontend when fields change later?" When you can answer these questions, you are no longer just a frontend developer who can write pages, but a full-stack engineer who can deliver a complete business loop. Haha, it sounds a bit intense, but from another perspective, this is also one of the easiest paths for frontend colleagues to break through the ceiling.

1. What Problem Does This Article Solve?

If you have been writing frontend for a long time, opening a Java backend project for the first time can easily raise several questions:

This article solves only one thing: helping you build the overall map of the current backend project.

You don't need to fully master Redis for now, nor understand all the APIs of MyBatis-Plus, nor grasp order transactions and payment callbacks all at once. You just need to first know where these backend capabilities are located in the project, what problems they solve, and which path to follow for future learning.

You can treat this article as a project tour given by a senior colleague when you first enter a new company's backend project: first tell you the project directory, tell you which API to start reading from, tell you not to haphazardly write business logic into the Controller, and also tell you why the database is the data truth of the backend system.

The root directory of the current project is:

/Users/zz/code/learning/fullstack-mall

The project README defines it as a "second-hand e-commerce full-stack learning project," currently focusing on backend learning, having covered stages 0-9. That is to say, this is not an empty shell demo; it already contains backend learning materials for products, categories, SKUs, shopping carts, orders, payments, Redis caching, etc. Your learning path should not be memorizing annotations in isolation but gradually deepening around these real business chains.

After this article, you should be able to:

  1. Clearly state the difference between backend/contract and backend/service;
  2. Clearly state what problems pom.xml, application.yml, and docker-compose.dev.yml solve respectively;
  3. Follow GET /api/products/{id} to find ProductController.detail() and IProductFacade.getPublishedProduct();
  4. Roughly understand the responsibility boundaries of Controller, Facade, DbService, Mapper, Entity, SQL;
  5. Know why subsequent learning needs to first supplement Java, Spring Boot, MySQL, MyBatis-Plus, JWT, and Redis basics.

2. Analogizing Backend Projects with Frontend Knowledge

In frontend projects, we are used to seeing structures like this:

frontend-app/
├── package.json
├── src/
│   ├── main.ts
│   ├── router/
│   ├── pages/
│   ├── components/
│   ├── api/
│   ├── stores/
│   └── types/
└── vite.config.ts

You probably know:

Opening the current backend project, you will see another set of names:

fullstack-mall/
├── backend/
│   ├── pom.xml
│   ├── contract/
│   └── service/
├── docs/
├── sql/
└── docker-compose.dev.yml

Don't be intimidated by Java terminology. You can temporarily analogize like this:

Familiar Frontend Thing Backend Corresponding Concept Location in This Project Key Difference
package.json pom.xml backend/pom.xml, backend/service/pom.xml Maven not only installs dependencies but also handles Java compilation, testing, packaging, and multi-module relationships
main.ts Spring Boot startup class FullstackMallApplication.java Backend runs persistently after startup, listening for HTTP requests
Vue Router Controller URL mapping *Controller.java Controller is not a page route; it is the server's HTTP entry point
Axios request type Request DTO contract/*Request.java DTO is a runtime Java object that participates in parameter binding and validation
Axios response type Response DTO contract/*Response.java Before the backend actually returns JSON, it first assembles a Java Response object
api/product.ts Facade contract IProductFacade.java Facade represents backend external use cases, not just a request function
composable / service Facade implementation ProductFacade.java Facade handles permissions, business orchestration, data transformation
State management store Database / Cache MySQL / Redis Frontend state is usually in the browser; backend data must serve all users and be persistent
mock data seed SQL / test data sql/02_seed.sql, test resources Backend test data must comply with database constraints
Browser DevTools Logs, curl, IDEA Debug, DB queries Test classes, logs, SQL, Redis CLI Backend problems often require cross-HTTP, Java, DB, cache localization

This analogy is just an introductory bridge and cannot be completely equated. For example, a Controller looks like a frontend route, but a Controller faces untrusted input from the network and must consider parameter validation, permissions, concurrency, and exception returns. Also, a DTO looks like a TypeScript interface, but a TypeScript interface doesn't exist after compilation, whereas a Java DTO is an object that will actually be created at runtime; Spring will bind the JSON request body to these objects and perform validation based on annotations.

The most important mindset change when transitioning from frontend to backend is: Frontend usually focuses on "what the user sees right now"; backend must focus on "whether all users, all requests, and all data remain correct under concurrency and failure conditions."

Take a product detail page as an example. Looking at this requirement from the frontend, you might think:

// Frontend-side illustrative code: this file does not exist in the current repo
async function fetchProductDetail(id: number) {
  const res = await axios.get(`/api/products/${id}`)
  return res.data.data
}

The frontend's focus is usually: what is the API path, what are the parameters, what are the return fields, how to handle loading, how to display error toasts.

Seeing the same requirement, the backend will continue to ask:

These questions are the reason for the layering of backend projects. Backend code is not split into layers to appear complex, but because different problems should be solved in different places.

3. Getting to Know Backend Core Concepts by Name

In this first article, we'll just get to know the names, without expanding on all the details.

3.1 Maven: The Backend Dependency and Build System

The parent backend project for the current project is backend/pom.xml. If you are familiar with frontend, you can first understand it as the package.json of the backend world, but it emphasizes modules, compilation, testing, and packaging more than package.json.

backend/pom.xml defines:

backend/service/pom.xml is the dependency list for the runnable backend service. There you can see dependencies like Spring Web, Validation, Redis, Security, OpenAPI, MyBatis-Plus, MySQL, H2, Testcontainers. Later, when you see "why can the project write Controllers," "why can it connect to MySQL," "why can it use Redis," you must return to this file to find the source of the dependencies.

3.2 Spring Boot: The Backend Application Runtime Container

Spring Boot can first be understood as a "backend application runtime framework." After the frontend's Vite dev server starts, it is responsible for serving page resources and hot updates; after Spring Boot starts, it is responsible for listening on an HTTP port, handing requests to Controllers, and managing various Beans in the project.

The startup class for the current project is:

backend/service/src/main/java/com/example/fullstackmall/service/FullstackMallApplication.java

You will later see many classes with annotations like @RestController, @Service, @Configuration. Their commonality is: these classes will be scanned and managed by Spring, becoming objects within the Spring container. The project often uses @Resource to inject one Bean into another, such as injecting IProductFacade into ProductController.

In the frontend, you might import a function like this:

// Frontend-side illustrative code
import { getProductDetail } from '@/api/product'

In the backend, it's common to hand objects over to Spring for management and then get them via dependency injection:

@Resource
private IProductFacade productFacade;

This is not a simple syntactic difference. Backend objects may involve transaction proxies, security proxies, lifecycles, configuration injection, thread safety, etc., so they are uniformly managed by the Spring container.

3.3 Controller: The HTTP Request Entry Point

The Controller is the layer most like "routing" in the backend. The public product API in the current project is at:

backend/service/src/main/java/com/example/fullstackmall/service/product/ProductController.java

This class has @RestController and @RequestMapping("/api/products"). @RequestMapping indicates that the common path prefix for this group of APIs is /api/products.

The detail() method inside has @GetMapping("/{id}"), so its corresponding full path is:

GET /api/products/{id}

If the frontend requests:

GET /api/products/1001

Spring will bind the 1001 in the path to the method parameter id, then execute ProductController.detail().

But note: The Controller should not carry complex business logic. It mainly does a few things: receive HTTP parameters, call the Facade, wrap a unified response, and return it to the frontend. Real business rules should not be piled into the Controller.

3.4 Contract: The Backend External Contract

The current project has a separate module:

backend/contract

You can understand it as the "API contract layer that both frontend and backend should care about." This is where Request, Response, enum, and I...Facade type external models are placed.

For example, the Facade interface for the product module is at:

backend/contract/src/main/java/com/example/fullstackmall/contract/product/IProductFacade.java

This interface defines what capabilities the product module provides externally: creating products, changing status, admin queries, public queries, public details, updating subtitles, etc.

Why have a contract? Because the backend cannot just write "internal implementation." The frontend cares about "what APIs can I call, what fields do I submit, what fields do I get back." The backend internally cares about "how to query the database, how to validate, how to assemble data." contract acts like a boundary line, making the external structure more stable.

When writing TypeScript on the frontend, you might define:

// Frontend-side illustrative code
type ProductDetail = {
  id: number
  title: string
  subtitle: string
  description: string
}

The backend's ProductDetailResponse plays a similar role, but it's not just a compile-time type hint; it will actually participate in JSON serialization and finally be returned to the browser.

3.5 Facade: The Business Orchestration Layer

The term Facade might be a bit unfamiliar to frontend colleagues. You can first analogize it to "business service / composable in the frontend," but the backend Facade has heavier responsibilities.

In this project, the Controller usually does not directly operate the database but calls I...Facade. The Facade implementation class is responsible for:

For example, the implementation class for the product module is:

backend/service/src/main/java/com/example/fullstackmall/service/product/ProductFacade.java

Later, when discussing product details, we will follow ProductController.detail() into ProductFacade.getPublishedProduct(), and then see how it decides to check Redis first or fall back to MySQL.

3.6 Entity, Mapper, DbService: Data Access Related Layers

The backend ultimately needs to handle persistent data. Frontend state may disappear after refreshing the page, but the backend system needs to store data like products, orders, payments, and users long-term. The current project mainly uses MySQL to store business data.

These types of files often appear together:

ProductEntity.java
ProductMapper.java
ProductDbService.java

You can first understand them like this:

For example, ProductEntity corresponds to the mall_product table, ProductMapper extends MyBatis-Plus's BaseMapper<ProductEntity>, and ProductDbService further encapsulates actions like querying products and updating products.

You don't need to memorize all the syntax of MyBatis-Plus right now. Just know this for now: The backend does not directly use JSON as a database; the backend maps database rows to Java Entities, then assembles them into Responses through the business layer to return to the frontend.

3.7 SQL: The Final Landing Point of Database Structure

The database table structure for the current project is mainly in:

sql/01_schema.sql

This defines tables for products, categories, SKUs, shopping carts, orders, payments, etc. For the backend, the database is not an optional "place to store data," but the ultimate guarantee for many business rules: primary keys, unique constraints, indexes, field types, non-null constraints, and status fields all affect system behavior.

For example, the frontend page can restrict a title as required on the form, but truly reliable constraints must be implemented in backend validation and database structure. Because anyone can bypass the frontend page and directly call the API; the backend cannot trust that "the frontend will definitely pass the correct data."

3.8 Redis: Server-Side Shared Cache

Redis is used in stage 9 of this project for product detail caching. You can first analogize it to memory cache or localStorage in the frontend, but there are several key differences:

In this project's product detail chain, Redis is the performance layer in front of MySQL. Public product details first try to check the cache; if the cache hits, one less MySQL query is made; if the cache misses, or Redis degrades, it falls back to MySQL. Later articles 7 and 14 will specifically cover Redis; for now, you just need to know its position in the project.

3.9 Spring Security and JWT: Authentication and Authorization Entry Point

Frontend colleagues are usually familiar with Tokens: after a successful login, get a Token, store it locally, and put it in the Authorization header for subsequent requests. What the backend needs to do is the reverse: after receiving a request, parse the Token, determine who this user is, and whether they have permission to access the current API.

This project uses Spring Security and JWT. Security-related code is mainly in:

backend/service/src/main/java/com/example/fullstackmall/service/security
backend/service/src/main/java/com/example/fullstackmall/service/config/SecurityConfig.java
backend/service/src/main/java/com/example/fullstackmall/service/auth

Later, when discussing login authentication, we will specifically explain the difference between 401 and 403. For now, just remember one sentence: The frontend is responsible for carrying the Token; the backend is responsible for verifying whether the Token is trustworthy and deciding whether access to the API is allowed.

4. Corresponding Files in This Project

First, look at a project directory diagram:

flowchart TD
    A[fullstack-mall Root Directory] --> B[README.md\nProject Positioning & Reading Entry]
    A --> C[backend/\nJava Backend Project]
    A --> D[docs/\nLearning Documents]
    A --> E[sql/\nMySQL Table Structure & Seed Data]
    A --> F[docker-compose.dev.yml\nLocal MySQL & Redis]

    C --> C1[backend/pom.xml\nParent Project & Version Management]
    C --> C2[contract/\nExternal Contract]
    C --> C3[service/\nRunnable Service]

    C2 --> C21[Request / Response / enum]
    C2 --> C22[I...Facade Interfaces]

    C3 --> C31[Controller\nHTTP Entry]
    C3 --> C32[Facade\nBusiness Orchestration]
    C3 --> C33[DbService\nDatabase Business Encapsulation]
    C3 --> C34[Mapper / Entity\nTable Mapping & SQL Entry]
    C3 --> C35[Security / Cache / Config\nSecurity, Cache, Configuration]

This diagram first solves the problem of "too many files, don't know where to look." You can set your reading order as:

  1. First look at the root directory README.md to confirm what the project does and what stage it has reached;
  2. Look at backend/pom.xml to confirm the Java version, Spring Boot version, and module split;
  3. Look at backend/service/pom.xml to confirm what backend capabilities this service uses;
  4. Find the simplest Controller, for example, ProductController.java;
  5. Jump from the Controller to IProductFacade.java, then to ProductFacade.java;
  6. When you need to query the database, look at Entity, Mapper, DbService;
  7. When you need to confirm fields, look at sql/01_schema.sql.

Don't start by memorizing the table structure from sql/01_schema.sql end-to-end on the first day, nor open the Redis cache service to dig into exception branches on the first day. The biggest fear when reading a new project is "starting from the most complex place," which easily leads to frustration. The correct way is to start from the most familiar HTTP request entry point and gradually expand along the call chain.

Below are the most important files for this first article:

File What You Need to Know Now
README.md The project is a second-hand e-commerce full-stack learning project, currently focused on backend, having completed stages 0-9
backend/pom.xml Maven parent project, defines Java 21, Spring Boot 3.5.16, multi-module structure
backend/contract/pom.xml External contract module, holds Request, Response, Facade interfaces
backend/service/pom.xml Runnable service module, includes Web, Validation, Security, Redis, MyBatis-Plus, MySQL dependencies
docker-compose.dev.yml Startup configuration for local MySQL 8.4 and Redis 7.4
backend/service/src/main/java/com/example/fullstackmall/service/FullstackMallApplication.java Spring Boot startup class
backend/service/src/main/java/com/example/fullstackmall/service/product/ProductController.java Public product API entry point
backend/contract/src/main/java/com/example/fullstackmall/contract/product/IProductFacade.java Product module external use case contract
backend/service/src/main/java/com/example/fullstackmall/service/product/ProductFacade.java Product business orchestration implementation
backend/service/src/main/java/com/example/fullstackmall/service/product/entity/ProductEntity.java Java Entity corresponding to the product table
backend/service/src/main/java/com/example/fullstackmall/service/product/mapper/ProductMapper.java Product table MyBatis-Plus Mapper
sql/01_schema.sql Database table structure

5. A Request Chain Diagram: From Frontend Page to Backend Layers

Now let's string together a familiar scenario: a product detail page requesting product details.

The frontend-side illustrative code might be:

// Frontend-side illustrative code: this file does not exist in the current repo
async function loadProductDetail(productId: number) {
  const response = await axios.get(`/api/products/${productId}`)
  return response.data.data
}

The actual backend entry point is in ProductController.detail(). To fully understand the chain, first look at this diagram:

sequenceDiagram
    participant FE as Vue Page\nIllustrative
    participant HTTP as HTTP Request
    participant Security as Spring Security\nFilter Chain
    participant Controller as ProductController
    participant Facade as IProductFacade\nProductFacade
    participant Cache as ProductDetailCacheService\nRedis
    participant Db as ProductDbService
    participant Mapper as ProductMapper
    participant MySQL as MySQL

    FE->>HTTP: GET /api/products/1001
    HTTP->>Security: Enter Backend Service
    Security->>Controller: Anonymous Public API Passed Through
    Controller->>Facade: getPublishedProduct(1001)
    Facade->>Cache: Try to Read Product Detail Cache
    alt Cache Hit
        Cache-->>Facade: Return Cached Detail
    else Cache Miss or Degraded
        Facade->>Db: Query Public Product Detail
        Db->>Mapper: Call MyBatis-Plus / SQL
        Mapper->>MySQL: Query mall_product etc. tables
        MySQL-->>Mapper: Return Data Rows
        Mapper-->>Db: Map to Entity
        Db-->>Facade: Return ProductEntity
        Facade->>Cache: Backfill Cache
    end
    Facade-->>Controller: ProductDetailResponse
    Controller-->>FE: ApiResponse

In this diagram, don't get stuck on Redis and MyBatis-Plus details first. You need to establish 3 core understandings first.

First, HTTP requests do not directly access the database. The request sent by the frontend first reaches the Spring Boot backend service, then is picked up by the Controller. The Controller is just the entry point, not the database access layer.

Second, business logic has a dedicated place. This project uses Facade for business orchestration. For example, for public product details, judging whether the product is listed, whether the category is enabled, whether to use cache, and which fields to return—these should not be scattered in the Controller.

Third, database and cache are backend internal details. The frontend only sees JSON, but the backend must decide whether the data comes from Redis or MySQL. Redis is the performance layer; MySQL is the source of data truth. Later, when you learn Redis, you will know why you need to delete the cache after modifying a product, and why a Redis failure shouldn't make the public detail API completely unavailable.

6. Reading Source Code Section by Section: Starting from ProductController

When reading backend source code for the first time, don't be greedy. We'll only read the public product detail entry point.

File path:

backend/service/src/main/java/com/example/fullstackmall/service/product/ProductController.java

The core information of this class is:

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @Resource
    private IProductFacade productFacade;

    @GetMapping("/{id}")
    public ApiResponse<ProductDetailResponse> detail(
            @PathVariable Long id,
            HttpServletRequest servletRequest
    ) {
        ProductDetailResponse response = productFacade.getPublishedProduct(id);
        return ApiResponse.success(response, TraceIdContext.get(servletRequest));
    }
}

Let's translate line by line from a frontend perspective.

6.1 @RestController: This is an HTTP entry class that returns JSON

You can understand @RestController as telling Spring: the methods in this class are to be exposed as HTTP APIs, and the return values will usually be converted to JSON.

In frontend routing, you might write:

// Frontend-side illustrative code
{
  path: '/products/:id',
  component: ProductDetailPage
}

But a Controller is not a page route. Frontend routing determines which page the browser displays; a backend Controller determines which Java method handles a specific HTTP request received by the server.

6.2 @RequestMapping("/api/products"): Common Path Prefix

This indicates that all APIs under the current class start with /api/products. You can understand it as the base path for uniformly encapsulating product APIs in a frontend api/product.ts file.

6.3 @Resource private IProductFacade productFacade: Dependency Injection

This line indicates that the Controller needs a product business object, but it doesn't new it itself; instead, it lets Spring inject it.

In the frontend, you often import a function or object. In Java backend, you can also new objects, but in Spring projects, business components are usually managed by the Spring container. Reasons for this include: unified lifecycle, easier configuration, easier testing, support for transaction proxies, and support for security and aspect capabilities.

For now, just remember: seeing @Resource means this class depends on another Spring-managed Bean.

6.4 @GetMapping("/{id}"): This is the GET Product Detail API

@GetMapping("/{id}") combined with the class-level /api/products becomes:

GET /api/products/{id}

@PathVariable Long id means the {id} in the path will be bound to the Java parameter id.

If the request is:

GET /api/products/1001

Then the id in the method is 1001.

6.5 productFacade.getPublishedProduct(id): Handing Business to Facade

The Controller did not query the database itself, nor did it judge the product status itself; it handed the matter to productFacade.

This is a very important style in this project: Controller handles HTTP, Facade handles business orchestration.

If you add new APIs in the future, never dump all the logic into the Controller. You should first ask: is this a parameter receiving problem, a business rule problem, or a database access problem? Different problems should be placed in different layers.

6.6 ApiResponse.success(...): Unified Response Format

The frontend hates it most when every API returns a different structure. Some APIs return { data }, some return { result }, and some directly return a string on failure. Backend projects usually define a unified response structure.

The current project uses ApiResponse<T>. The Controller finally returns:

ApiResponse.success(response, TraceIdContext.get(servletRequest))

You can first understand this as uniformly wrapping a layer: the business data is response, and a traceId is included to facilitate troubleshooting.

Later, when the frontend gets the response, what it sees is usually not a bare ProductDetailResponse, but something like:

{
  "code": "SUCCESS",
  "message": "success",
  "data": {
    "id": 1001,
    "title": "..."
  },
  "traceId": "..."
}

Specific fields are subject to the ApiResponse.java in the project. Article 3 will specifically cover Request, Response, and unified returns.

7. Jumping from Controller to IProductFacade

Now let's look at the interface called by the Controller:

backend/contract/src/main/java/com/example/fullstackmall/contract/product/IProductFacade.java

It is a Java interface. For frontend colleagues, you can first understand an interface as an "external capability list." What capabilities the product module exposes can be seen here.

You will see methods like these:

This is very valuable for frontend-to-backend transitions. Because you can first look at the interface list without looking at the implementation, quickly knowing what business use cases the product module supports.

This is like first opening api/product.ts in a frontend project:

// Frontend-side illustrative code
export function getPublishedProduct(id: number) {}
export function queryPublishedProducts(params: ProductQuery) {}
export function updateProductSubtitle(id: number, body: SubtitleUpdate) {}

The difference is: frontend api/product.ts is "calling backend APIs"; backend IProductFacade is "defining backend business capabilities." Its implementation is usually in ProductFacade.java.

When reading backend source code, you can follow this order:

  1. Controller: What is this HTTP API;
  2. Facade interface: What is this business capability called;
  3. Facade implementation: How is this capability orchestrated;
  4. DbService / CacheService: Where does the data come from;
  5. Mapper / Entity / SQL: How is the table ultimately queried or updated.

This reading order is much more effective than randomly opening files.

8. Why So Many Layers?

Frontend colleagues often ask: why can't the backend be simpler? For example, one Controller directly queries the database and returns JSON, isn't that enough?

For a very small demo, of course, it's possible. But an e-commerce project, even a learning project, will quickly encounter complex problems:

If all logic is written in the Controller, it becomes hard to maintain after a few hundred lines. The purpose of layering is to make each file only bear the responsibility it should bear.

Look at this responsibility boundary diagram:

flowchart LR
    A[Controller\nHTTP Entry] --> B[Facade\nBusiness Orchestration]
    B --> C[CacheService\nCache Strategy]
    B --> D[DbService\nDatabase Business Operations]
    D --> E[Mapper\nSQL / CRUD Entry]
    E --> F[MySQL\nData Truth]
    B --> G[TransactionService\nCross-Table Transactions]
    G --> D

    H[contract\nRequest / Response / enum / IFacade] -.Defines External Contract.-> A
    H -.Defines Business Capabilities.-> B

You can remember each layer in one sentence:

These layers are not for "architectural beauty" but to place complexity in the right places.

9. Look at Maven and Dependencies First: What Capabilities Does This Backend Project Have?

When looking at a frontend project, you usually look at package.json first, because it tells you whether it uses Vue or React, Vite or Webpack, Pinia or Redux. Similarly for the backend, look at pom.xml first.

The current project has 3 important Maven files:

backend/pom.xml
backend/contract/pom.xml
backend/service/pom.xml

backend/pom.xml is the parent project. From here you can know:

backend/contract/pom.xml is the contract module. It depends on Lombok and Validation API, indicating this is mainly for requests, responses, enums, and interface declarations, not a runnable service.

backend/service/pom.xml is the real service module. The dependencies here can tell you what backend capabilities the project has:

Dependency Direction Description Which Article to Learn Later
Spring Web Write HTTP Controllers, return JSON Articles 2, 3, 8
Validation Validate Request parameters Articles 3, 15
Spring Data Redis Use Redis cache Articles 7, 14
Spring Security Authentication and authorization Article 6
JJWT Create and verify JWT Article 6
Springdoc OpenAPI Generate API documentation Briefly mentioned in Article 3
MyBatis-Plus Operate MySQL tables Article 5
Druid Database connection pool Will be recognized in Articles 4, 5
MySQL Connector Connect to MySQL Article 4
H2 / Testcontainers Used for automated testing Mentioned in later debugging and testing articles

This step is very much like looking at frontend dependencies. Just as seeing vue-router in the frontend tells you there's routing, seeing spring-boot-starter-web in the backend tells you Controllers can be written; seeing pinia in the frontend tells you there's state management, seeing mybatis-plus in the backend tells you the project uses ORM / Mapper to operate the database.

10. Local Environment: Why docker-compose is Needed

Frontend projects can often be run with pnpm dev, because the page itself may not depend on a local database. But backend services usually depend on external infrastructure, like MySQL and Redis.

The local dependencies for the current project are in:

docker-compose.dev.yml

This file defines two services:

Frontend colleagues can understand it like this:

flowchart TD
    A[Spring Boot Backend Service] --> B[MySQL\nPersistent Business Data]
    A --> C[Redis\nCache Hot Data]
    D[curl / Browser / Frontend Page] --> A

If MySQL is not started, many backend query and write APIs will not work properly. Because data like products, orders, and users cannot only exist in Java memory.

If Redis is not started, depending on the code design, some cache functions will degrade, and some tests may be skipped. The current project README mentions that stage 9 has already implemented Redis fail-open degradation, meaning public product details should try to fall back to MySQL when Redis fails, rather than making it completely unavailable to users. Just know this point for now; the Redis article will go deeper later.

Your common local startup approach is:

# Start MySQL and Redis
docker compose -f docker-compose.dev.yml up -d mysql redis

# Start the backend service
cd backend
mvn -pl service -am spring-boot:run

If you just want to quickly see if the service is alive, you can request the health check API. The specific API can be found later from HealthController.java.

11. Understanding Unified Response and traceId from a Frontend Calling Perspective

When the frontend calls backend APIs, it most desires a stable response structure. For example:

// Frontend-side illustrative code
const res = await axios.get('/api/products/1001')
if (res.data.code === 'SUCCESS') {
  render(res.data.data)
} else {
  showToast(res.data.message)
}

Backend projects usually unify the return structure so the frontend doesn't need to write a special parsing logic for each API. The Controller in the current project returns ApiResponse<T>, which is this unified response idea.

TraceIdContext.get(servletRequest) is related to troubleshooting. When a frontend user reports "product details won't open," you can't just say "it's fine on my end." The backend needs to locate what happened with this request through traceId, logs, API path, user ID, and error codes.

When troubleshooting, the frontend looks at the browser's Network panel; the backend looks at logs, traceId, database, Redis, tests, and Debug. traceId is like a thread that strings together the flow of a single request in the backend.

12. Things Not to Rush Into at This Stage

You have already seen many backend terms: Redis, MyBatis-Plus, JWT, transactions, Mapper, Entity, SQL, cache penetration, idempotency, state machines. Don't rush to learn them all.

This first article only requires you to build a map. The following content will be gradually expanded in subsequent articles:

12.1 Java and Maven

You will later need to know Java class, interface, annotations, generics, collections, exceptions, time, money, Maven dependencies, module builds. But for now, just know: Maven handles backend dependencies and builds; Spring Boot is responsible for running the Java service.

12.2 Spring Boot Web

You will later need to master @RestController, @RequestMapping, @GetMapping, @PostMapping, @RequestBody, @PathVariable, @Valid. But for now, just know: Controller is the HTTP entry point.

12.3 MySQL and MyBatis-Plus

You will later need to understand tables, fields, primary keys, indexes, SQL, transactions, Entity, Mapper, Wrapper, pagination. For now, just know: MySQL is the data truth; MyBatis-Plus helps Java code operate MySQL.

12.4 Spring Security and JWT

You will later need to understand login, Token, Filter, SecurityContext, 401, 403, admin permissions. For now, just know: the frontend carries the Token; the backend verifies the Token and permissions.

12.5 Redis

You will later need to understand key, value, TTL, serialization, Cache Aside, cache penetration, breakdown, avalanche, write invalidation, fail-open. For now, just know: Redis is a server-side shared cache; MySQL is the source of business truth.

12.6 Transactions and State Machines

You will later need to understand why orders need transactions, why inventory needs atomic deduction, why payment callbacks need idempotency, why timeout order closure needs conditional status updates. For now, just know: the backend handles not only "successful requests" but also "concurrency, failures, repeated requests, external callbacks."

13. How to Run and Verify Locally

This first article doesn't require you to fully run all business logic, but you need to know where the basic commands are.

13.1 Check Project Status

In the project root directory:

pwd
find . -maxdepth 2 -type d | sort

You should see directories like backend, docs, sql.

13.2 Start Local Dependencies

docker compose -f docker-compose.dev.yml up -d mysql redis

This command starts MySQL and Redis according to docker-compose.dev.yml. MySQL is mapped to local port 3308, Redis to local port 6379.

If you don't have Docker yet, don't get stuck here. You can read the code and documentation first. Handle the Docker environment when you actually start API joint debugging.

13.3 Start the Backend Service

cd backend
mvn -pl service -am spring-boot:run

Here, -pl service -am can be roughly understood as: start the service module and automatically build the modules it depends on. Because service depends on contract, Maven will handle them together.

13.4 Request APIs with curl

Later you can use curl to simulate frontend requests. For example, product details:

curl -i http://localhost:8080/api/products/1001

If you usually only use the browser and Axios, it's recommended to start getting used to curl. curl allows you to detach from the page and directly verify backend APIs. Backend development often needs to first prove whether the API itself is correct, then discuss how the frontend page should display it.

14. Common Mistakes

Mistake 1: Reading the Most Complex Business Logic Right Away

Many people open the project and directly look at orders, payments, Redis caching, resulting in more confusion the more they read. The correct approach is to start from a simple public GET API, such as GET /api/products/{id}. First establish the basic chain of Controller → Facade → Data layer, then look at complex branches.

Mistake 2: Treating the Controller as a Universal File

When writing frontend pages, a component might contain requests, state, events, and display. The backend cannot be mixed so casually. The Controller should not directly write complex business logic, nor should it scatter SQL directly. Otherwise, permissions, transactions, caches, and exceptions become hard to maintain.

Mistake 3: Confusing DTO, Entity, and Database Table

Request / Response faces the API, Entity faces the database table, SQL defines the real table structure. Their fields may be similar, but responsibilities differ. For example, the database might have created_by, but the public product detail Response doesn't necessarily need to expose this field to the frontend.

Mistake 4: Thinking Frontend Validation is Sufficient for Security

Frontend forms can restrict required fields, length, and format, but the backend cannot trust the frontend. Because users can bypass the page and directly call the API. Truly reliable validation must be jointly implemented in backend Request validation, business validation, and database constraints.

Mistake 5: Thinking Redis is a Database

Redis is fast, but in this project, Redis is mainly a cache layer. Product detail caching can speed up reads, but the business truth is still in MySQL. After modifying a product, cache invalidation must be considered; when Redis fails, a degradation strategy must be considered.

Mistake 6: Only Looking at the Success Path, Not the Failure Path

When learning APIs on the frontend, it's easy to only look at 200 success. But the backend must define failures: what to return for wrong parameters, what to return when not logged in, what to return when lacking permissions, what to return when a product doesn't exist, what to return when inventory is insufficient, what to do for duplicate payment callbacks. Every subsequent article will practice failure scenarios.

Mistake 7: Not Reading README and docs, Directly Searching Globally

The current project documentation is already very rich. The README explains the project stages, code responsibilities, and reading entry points; docs/backend-basics has a lot of basic documentation. Read the entry documents first, then read the source code along the chain; this is much more efficient than blind searching.

15. Chapter Exercises

Please open the project and complete the following exercises yourself. Don't rush to write code, just do positioning and understanding.

Exercise 1: Find the Startup Class

Find:

backend/service/src/main/java/com/example/fullstackmall/service/FullstackMallApplication.java

Answer: Why is this class like the frontend's main.ts? What is its relationship with ProductController.java?

Exercise 2: Find the Product Detail API

Find:

backend/service/src/main/java/com/example/fullstackmall/service/product/ProductController.java

Answer: Which Java method does GET /api/products/{id} correspond to? Which parameter does the {id} in the path bind to?

Exercise 3: Find the Product Business Contract

Find:

backend/contract/src/main/java/com/example/fullstackmall/contract/product/IProductFacade.java

Answer: What capabilities does the product module provide externally? Which look like public APIs? Which look like admin APIs?

Exercise 4: Find Maven Dependencies

Open:

backend/service/pom.xml

Answer: Can you find dependencies related to Spring Web, Spring Security, Redis, MyBatis-Plus, MySQL? What subsequent learning topics do they correspond to?

Exercise 5: Draw Your Own Call Chain

Draw in your own words:

Frontend request GET /api/products/1001
  -> ProductController.detail
  -> IProductFacade.getPublishedProduct
  -> ProductFacade
  -> CacheService / DbService
  -> Mapper
  -> MySQL
  -> ProductDetailResponse
  -> ApiResponse
  -> Frontend page

If you don't know the specific code inside ProductFacade yet, don't worry. This first article only requires you to know where the next stop is.

16. Summary of Article 1: Build the Map First, Then Dive into Details

The easiest mistake for frontend-to-backend transitions is treating the backend as "an API file that connects to a database." Real backend projects need to solve much more than that: request entry, parameter validation, permissions, business status, transactions, database constraints, caching, logging, testing, failure degradation, concurrency safety. Precisely because the problems are complex, backend projects need layering.

The basic map of this project can be summarized as:

README.md: First know what the project is
backend/pom.xml: Know Java / Spring Boot / Maven modules
backend/contract: Know external Request / Response / Facade interfaces
backend/service: Know Controller / Facade / DbService / Mapper / Cache / Security implementations
sql: Know MySQL table structure and data constraints
docker-compose.dev.yml: Know how to start local MySQL / Redis
docs: Know the learning path and stage descriptions

If you only remember one sentence, remember this:

Start from the frontend request, find the Controller first; from the Controller find the Facade; from the Facade then look at cache, database, and transactions. Don't get bogged down in all backend terminology at the beginning.

This is your first main thread for reading the current backend project.

16.1 A Source Code Reading Rule for Frontend Colleagues

Add one more very practical source code reading rule: Always start from "user actions," never from "framework terminology."

For example, if you want to learn product details, don't first ask "what are all the methods of RedisOperatorClient," nor "how many ways are there to write MyBatis-Plus Wrappers." You should first reconstruct the user action: the user opens the product detail page, the page needs product title, subtitle, description, price, inventory, etc., so it initiates GET /api/products/{id}. Starting from this action, you will naturally find the Controller; the Controller only serves as an entry point, so you continue to find the Facade; the Facade finds it needs data, so you continue to look at cache and database; when database fields are unclear, go back to the SQL table structure. Reading code this way, backend knowledge will gradually grow around the business, rather than becoming a pile of isolated terms.

This also corresponds to the experience of learning a new frontend project. You wouldn't read all the component library source code on the first day; instead, you'd open a page first, look at its routing, APIs, state, and component breakdown. The backend is the same: first choose a small API as an entry point, then follow the call chain. Every time you encounter an unfamiliar concept, just ask three questions first: What problem does it solve? Which file is it in the current project? If it errors, what phenomenon will the frontend see? These three questions are more important than rote memorization of annotations.

17. Next Chapter Preview

Next, we will enter Basic Chapter 2: Java, Maven, and Spring Boot Startup Basics.

You will learn:

After learning the next chapter, you will have a clearer understanding of "why this project can run," and then Chapter 3 will specifically cover Controller, Request, Response, and unified returns.