项目全景 + 第一条完整后端链路

适用人群 :会 Vue,Java / Python 零基础

今日目标 :看懂项目结构,跟完「实施计划列表」从浏览器到数据库的完整流程

预计耗时 :8~10 小时(可分 3 段完成)

今日不写复杂代码,以「读代码 + 画链路 + 浏览器验证」为主


学习前提:你需要先知道的 3 件事

1. MES 项目 = 前端 + Java 后端(+ 巡检时才用 Python)

复制代码
mes/
├── service-front/     ← 前端(Vue 3,你会的)
└── enmo_support/      ← Java 后端(今天要学的重点)

巡检分析还依赖独立的 Python 项目(BethuneAnalysis),Day 1 只了解,不深学

2. 前端请求有两条「通道」(非常重要)

打开 vue.config.js,本地开发配了两个代理:

33:49:D:\mes\service-front\vue.config.js 复制代码
    proxy: {
      '/api': {
        target: 'http://localhost:8080/',
        changeOrigin: true,
        pathRewrite: {
          '^/api': '/'
        }
      },
      '/esapi': {
        target: 'http://localhost:8084/',
        changeOrigin: true,
        pathRewrite: {
          '^/esapi': '/'
        }
      }
    }
通道 前端 baseURL 本地转发到 用途
/api/ ajax({ proxy: '/api/' }) 8080 端口 登录等公共接口
/esapi/ ajax() 默认 8084 端口 MES 主业务(计划、故障、巡检...)

打开 utils/ajax.ts 看默认值:

46:55:D:\mes\service-front\src\utils\ajax.ts 复制代码
export function ajax(options: any): any {
  const config = {
    baseURL: options.proxy || '/esapi/',
    url: options.url,
    method: options.method || 'get',
    params: options.params || {},
    data: options.data || {},
    headers: options.headers || {},
    responseType: options.responseType || 'json'
  }

结论:

  • 登录走 /api/ → 8080
  • 计划列表走 /esapi/ → 8084(enmo_support

3. Java 后端固定四层结构(背下来)

复制代码
Controller  →  接 HTTP 请求(类似 apis/*.ts)
Service     →  写业务逻辑(类似 composable / 页面里的 methods)
Dao         →  访问数据库(类似直接写 SQL 的那一层)
Model       →  数据结构(类似 TypeScript interface)

上午(9:00~12:00):建立项目地图


任务 1:浏览前端目录(60 分钟)

在 IDE 中打开 service-front/src/,按下面顺序看:

1.1 apis/ --- 所有接口定义(9 个文件)
复制代码
apis/
├── manage.ts        ← 最大(1300+ 行),计划/故障/登录/组织/统计
├── inspection.ts    ← 巡检(11 个页面用)
├── serviceOrder.ts  ← 电子服务单
├── weeklyReport.ts  ← 工作报告
├── resource.ts      ← 资源文章
├── doc.ts           ← 文档
├── common.ts        ← 公共
├── ai.ts            ← AI 聊天
└── index.ts         ← 统一导出

练习: 打开 apis/index.ts,看模块如何导出:

1:8:D:\mes\service-front\src\apis\index.ts 复制代码
export * from './manage'
export * from './resource'
export * from './common'
export * from './inspection'
export * from './ai'
export * from './doc'
export * from './serviceOrder'
export * from './weeklyReport'

页面里 import { getPlanListApi } from '@/apis' 就是这样来的。

1.2 views/ --- 页面(135+ 个)
目录 业务 对应 apis
sr/ 服务台:计划、故障、咨询 manage.ts
manage/ 管理:统计、工时、团队 manage.ts
organization/ 组织:合同、成员 manage.ts
inspection/ 巡检(11 页) inspection.ts
permission/ 权限 manage.ts

练习: 数一数 inspection/ 有几个文件(11 个),对比 manage/(30+)。巡检只是项目一小部分。

1.3 interfaces/ --- TypeScript 类型

前端 Plan 接口定义在 interfaces/manage.ts

218:234:D:\mes\service-front\src\interfaces\manage.ts 复制代码
export interface Plan {
  id: number
  createdBy: number
  createdByName: string
  createdTime: string
  daterange: string[]
  startDate: string
  endDate: string
  endRealTime: string
  status: any
  cost: string
  title: string
  deliver: string
  companyId: number
  executorId: number | undefined
  executorName: string

对照理解: 这相当于 Java 后端的 Plan.java,字段名基本一致,前后端才能对接。

1.4 统一返回格式
8:21:D:\mes\service-front\src\interfaces\index.d.ts 复制代码
export interface PageListRes<T> {
  total: number
  list: Array<T>
  operateCallBackObj: any
  [key: any]: any
}
export interface OperateRes {
  operateCallBackObj: any
  operateCallBackUrl: string
  operateCode: string | number
  operateMessage: string
  success: boolean
  ResponseData?: any
}
  • 列表接口:返回 { total, list }
  • 操作接口(保存/删除):返回 { success, operateMessage }

任务 2:浏览 Java 后端目录(60 分钟)

打开 enmo_support/src/main/java/com/enmo/enmo_support/

复制代码
enmo_support/
├── workbench/     ← 【最大】计划、故障、咨询、统计、服务单
├── user/          ← 用户、公司、合同、团队
├── content/       ← 知识库、文档、周报
├── perm/          ← 角色权限
├── security/      ← 登录、OAuth
├── bethune/       ← 巡检(Java 网关层)
├── common/        ← 公共:异常、注解、工具
├── aliyun/        ← OSS 文件
├── chat/          ← AI 聊天
└── search/        ← 搜索

每个包内部结构相同:

复制代码
workbench/
├── controller/    ← 接 HTTP(对应 apis/*.ts)
├── service/       ← 业务逻辑
│   └── Impl/      ← 实现类(真正写逻辑的地方)
├── dao/           ← 数据库访问
├── model/         ← 实体类(对应 interfaces/*.ts)
└── ...

练习:

  1. 打开 workbench/controller/,数 Controller 个数(15+)
  2. 打开 bethune/controller/,只有 2 个
  3. 建立直觉:先学 workbench,后学 bethune
Java 启动类
20:28:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\EnmoSupportApplication.java 复制代码
@SpringBootApplication
@EnableScheduling
@EnableFeignClients
@EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan(basePackages = {"com.enmo.enmo_support.*.dao", "com.enmo.enmo_support.*.mapper"})
public class EnmoSupportApplication {

    public static void main(String[] args) {
        SpringApplication.run(EnmoSupportApplication.class, args);
  • @SpringBootApplication:标记这是 Spring Boot 项目
  • @MapperScan:扫描所有 Dao 接口
  • @EnableFeignClients:支持远程调用 Python(巡检用)
  • main 方法:在 IDEA 里右键 Run 启动后端

任务 3:Java 零基础速读手册(60 分钟)

你不需要先学完 Java 再读项目,按下面「前端对照表」即可。

3.1 文件头部:package 和 import
java 复制代码
package com.enmo.enmo_support.workbench.controller;  // 包名 = 文件夹路径

import com.enmo.enmo_support.workbench.model.Plan;  // 导入其他类
import org.springframework.web.bind.annotation.*;

≈ 前端的 import { Plan } from '@/interfaces'

3.2 类上的注解(重点)

PlanController.java 为例:

29:37:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\workbench\controller\PlanController.java 复制代码
@Api(tags = "实施计划管理")
@Slf4j
@AllArgsConstructor
@EmcsController
@RequestMapping("/plan")
public class PlanController {
    private PlanService planService;
    private final PlanExecutorService planExecutorService;
注解 作用 前端类比
@EmcsController 标记为 REST 控制器 类似一个 api 模块
@RequestMapping("/plan") 基础路径 /plan url: 'plan/...' 前缀
@AllArgsConstructor 构造器自动注入依赖 自动 import 并初始化 service
@Slf4j 日志 console.log 的升级版

@EmcsController 本质是:

15:19:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\common\annotation\EmcsController.java 复制代码
@RestController
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Transactional(transactionManager = "transactionManager", propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
public @interface EmcsController {

= @RestController + 事务管理。

3.3 方法上的注解
39:49:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\workbench\controller\PlanController.java 复制代码
    @ApiOperation("实施计划列表")
    @GetMapping("/list")
    @PreAuthorize("hasAuthority('plan:query')")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "token", required = true, dataType = "string", paramType = "header"),
            ...
    })
    public PageInfo<Plan> findPlanList(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                       @RequestParam(required = false, defaultValue = "10") Integer pageSize,
注解 含义 前端对应
@GetMapping("/list") GET /plan/list ajax({ url: '/plan/list' })
@PostMapping("/save") POST /plan/save method: 'post'
@DeleteMapping("/delete/{id}") DELETE /plan/delete/123 url: `plan/delete/${id}`, method: 'delete'
@RequestParam URL 查询参数 params: { pageNum: 1 }
@RequestBody POST 请求体 JSON data: { title: '...' }
@PathVariable 路径里的变量 ``url: `plan/detail/${id}```
@PreAuthorize 权限校验 前端按钮 v-if + 后端二次校验
3.4 Java 类型对照
Java 含义 前端
Integer 可空整数 `number
String 字符串 string
List<Plan> Plan 数组 Plan[]
Boolean 布尔 boolean
void 无返回值 void

下午(14:00~18:00):跟完两条真实链路


任务 4:链路一 --- 登录(60 分钟)

Step 1:前端 Login.vue

用户点「登录」→ onSubmitsaveLogin

125:137:D:\mes\service-front\src\views\Login.vue 复制代码
    const saveLogin = async () => {
      let { data } = await submitLoginApi(state.loginForm)
      cbSuccess(data, () => {
        loginRecordApi()
        if (route.query.markedid && route.query.redirect) {
          let _redirect = route.query.redirect as string
          router.push({ path: _redirect, query: { markedid: route.query.markedid } })
        } else {
          router.push((route.query.redirect as string) || (isMobile() ? 'work' : '/'))
        }
      })
    }

表单数据:

102:107:D:\mes\service-front\src\views\Login.vue 复制代码
      loginForm: {
        bizType: 'mes',
        phoneNum: '',
        password: '',
        smsCode: ''
      }
Step 2:apis/manage.ts
21:27:D:\mes\service-front\src\apis\manage.ts 复制代码
export const submitLoginApi = (data = {}): Res<OperateRes> =>
  ajax({
    proxy: '/api/',
    url: 'login',
    method: 'post',
    data: data
  })

注意 proxy: '/api/' ,不是默认的 /esapi/

实际请求:

复制代码
POST http://localhost:8081/api/login
  → vue proxy 转发
  → POST http://localhost:8080/login
Step 3:ajax.ts 如何处理 token

请求发出时带 token:

62:64:D:\mes\service-front\src\utils\ajax.ts 复制代码
  if (store.getters.token && !isServiceOrderSharePage) {
    config.headers.Authorization = store.getters.token
  }

响应回来时保存 token:

22:27:D:\mes\service-front\src\utils\ajax.ts 复制代码
axios.interceptors.response.use(
  data => {
    const _token = data.headers.authorization
    if (_token) {
      store.commit('SetToken', _token)
    }

401/403 时跳转登录页:

66:82:D:\mes\service-front\src\utils\ajax.ts 复制代码
    if (err.response && [401, 403].includes(err.response.status)) {
      ...
        store.commit('LOGOUT')
        ...
          router.replace({
            name: 'Login',
            query: { redirect: _currentRoute.path }
          })
          Message(err.response.data.operateMessage || '请登录后操作')
登录链路图
复制代码
Login.vue 点击登录
  → submitLoginApi({ phoneNum, password, bizType: 'mes' })
  → ajax({ proxy: '/api/', url: 'login', method: 'post' })
  → POST /api/login → 代理到 8080
  → 响应头 authorization → 存入 Vuex
  → 后续请求自动带 Authorization 头

浏览器验证:

  1. 打开 DevTools → Network
  2. 登录,找到 login 请求
  3. 看 Request Headers 和 Response Headers 里的 authorization

任务 5:链路二 --- 实施计划列表(120 分钟,今日核心)

这是 MES 最典型的 Java 纯后端链路,后面 90% 接口都这个模式。

Step 1:前端页面 Plan.vue

页面加载时调用 fetchData()

169:187:D:\mes\service-front\src\views\sr\Plan.vue 复制代码
const fetchData = async () => {
  let {
    data: { total, list }
  } = await getPlanListApi(params)
  state.total = total
  if (isMobile()) {
    state.plans.push(...list)
  } else {
    state.plans = list
  }
}
...
fetchData()
const { formRef, params, setParams, search, onSubmit, operate } = useAdmq(fetchData)

params 来自 compositions/admq.ts(分页封装):

11:14:D:\mes\service-front\src\compositions\admq.ts 复制代码
  const params: Params = reactive({
    pageNum: 1,
    pageSize: 10
  })

模板渲染:

17:24:D:\mes\service-front\src\views\sr\Plan.vue 复制代码
      v-for="item in plans"
      :key="item.id"
      ...
      <div class="f16 c2b">{{ item.title }}</div>
      ...
        ><span class="c6">{{ item.startDate }} 至 {{ item.endDate }}</span>
Step 2:apis/manage.ts
303:307:D:\mes\service-front\src\apis\manage.ts 复制代码
export const getPlanListApi = (params = {}): Res<PageListRes<Plan>> =>
  ajax({
    url: '/plan/list',
    params: params
  })

没有写 proxy,走默认 /esapi/

复制代码
GET http://localhost:8081/esapi/plan/list?pageNum=1&pageSize=10
  → 代理到
  → GET http://localhost:8084/plan/list?pageNum=1&pageSize=10
Step 3:Java Controller
39:75:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\workbench\controller\PlanController.java 复制代码
    @ApiOperation("实施计划列表")
    @GetMapping("/list")
    @PreAuthorize("hasAuthority('plan:query')")
    ...
    public PageInfo<Plan> findPlanList(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                       @RequestParam(required = false, defaultValue = "10") Integer pageSize,
                                       @RequestParam(required = false) Integer companyId,
                                       ...
                                       @RequestParam(required = false) Boolean excludeEnded
    ) {
        Page<Plan> page = new Page<>(pageNum, pageSize);
        List<Plan> plans = planService.findList(page, companyId, companyName, startDate, endDate, title, status, mine, range, teamId, executorId, checkType, planType, contractId, accId,
                hasAccId, hasImplementationId, missingAccId, missingImplementationId, missingPreSalesCase, excludeEnded);
        return new PageInfo<>(plans);
    }

逐行解读:

java 复制代码
// 1. GET 请求,路径 = @RequestMapping("/plan") + @GetMapping("/list") = /plan/list
@GetMapping("/list")

// 2. 需要 plan:query 权限,没权限返回 403
@PreAuthorize("hasAuthority('plan:query')")

// 3. 从 URL 取参数,不传则默认值 pageNum=1, pageSize=10
@RequestParam(required = false, defaultValue = "1") Integer pageNum

// 4. 创建分页对象
Page<Plan> page = new Page<>(pageNum, pageSize);

// 5. 交给 Service 查数据
List<Plan> plans = planService.findList(page, ...);

// 6. 包装成 PageInfo 返回(含 total、list)
return new PageInfo<>(plans);
Step 4:Java Service(业务逻辑)

PlanServiceImpl.findList() 核心片段:

91:138:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\workbench\service\Impl\PlanServiceImpl.java 复制代码
        Integer createdBy = null;
        // 权限控制:sys、pa和团队管理员可以查看更多数据,其他用户只能看到自己相关的计划
        if (!UserUtils.isSys() && !userManagerService.isPA() && !userManagerService.isTA()) {
            executorId = UserUtils.getCurrentUserId();
            createdBy = UserUtils.getCurrentUserId();
        } else {
            ...
        }
        ...
        startPage(page.getPageNum(), page.getPageSize());
        List<Plan> planList = planDao.findList(companyName, startDate, endDate, title, status, executorId, companyId, null, rangeStart, rangeEnd, userIds, checkType, createdBy, planType, contractId, accId,
                hasAccId, hasImplementationId,
                missingAccId, missingImplementationId, missingPreSalesCase, excludeEnded);
        planList.forEach(plan -> {

Service 做两件事:

  1. 权限:普通用户只能看自己的计划
  2. 分页 + 查库startPage() 然后 planDao.findList()
Step 5:Java Dao + MyBatis SQL

Dao 接口:

15:21:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\workbench\dao\PlanDao.java 复制代码
@Mapper
public interface PlanDao {
    /**
     * 查询计划列表
     */
    List<Plan> findList(@Param("companyName") String companyName,
                        @Param("startDate") LocalDate startDate,
  • @Mapper:MyBatis 标记,Spring 自动实现
  • 只有方法声明,SQL 在 XML 里

SQL 文件 resources/mybatis/workbench/PlanMap.xml

4:32:D:\mes\enmo_support\src\main\resources\mybatis\workbench\PlanMap.xml 复制代码
    <select id="findList" resultMap="PlanMap">
        select
        ep.id,
        ep.created_by createdBy,
        ep.title,
        ce1.employee_name createdByName,
        ep.created_time createdTime,
        ep.company_id companyId,
        cc.name companyName,
        ep.start_date startDate,
        ep.end_date endDate,
        ep.status,
        ...
        from es_plan ep
        left join cs_employee ce1 on ep.created_by = ce1.created_by ...
        left join cs_company cc on ep.company_id = cc.id
        ...
        <where>
            <if test="title != null and title != ''">and lower(ep.title) like concat('%',#{title},'%')</if>
            <if test="status != null">and ep.status = #{status}</if>
  • from es_plan ep:主表
  • left join:关联公司、员工
  • <if test="...">:动态条件,有参数才拼进 SQL
Step 6:Model 实体类
17:37:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\workbench\model\Plan.java 复制代码
@Data
public class Plan {
    private Integer id;
    private Integer createdBy;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
    private Date createdTime;
    private Integer companyId;
    @Length(max = 128, message = "{title}{lengthMax}")
    private String title;
    private Date startDate;
    private Date endDate;
    @Length(max = 300, message = "{deliver}{lengthMax}")
    private String deliver;
    private Integer status;
  • @Data:Lombok 自动生成 getter/setter
  • 字段名 createdBy 对应 SQL 别名 created_by createdBy
  • 对应前端 interface Plan
完整链路图(建议手画一遍)
复制代码
【浏览器】打开 /plan 页面
    ↓
【Plan.vue】fetchData() 调用 getPlanListApi(params)
    ↓ params = { pageNum: 1, pageSize: 10, mine: false }
【apis/manage.ts】ajax({ url: '/plan/list', params })
    ↓ baseURL = '/esapi/'
【vue.config.js 代理】→ http://localhost:8084/plan/list?pageNum=1&pageSize=10
    ↓ Header: Authorization: xxx
【PlanController】@GetMapping("/list") findPlanList()
    ↓ @PreAuthorize 检查权限
【PlanServiceImpl】findList() 权限过滤 + startPage()
    ↓
【PlanDao】findList() 接口
    ↓
【PlanMap.xml】SELECT ... FROM es_plan WHERE ...
    ↓
【PostgreSQL】返回数据
    ↓
【PageInfo】包装 { total: 100, list: [...] }
    ↓ JSON
【Plan.vue】state.plans = list 渲染列表
浏览器验证(必做)
  1. 登录后打开 /plan
  2. Network 筛选 plan/list
  3. 填写:
项目 你的记录
完整 URL
Request Method GET
Query String pageNum, pageSize, mine...
Request Headers 的 Authorization 有/无
Response 结构 { total, list: [...] }
list0 字段 id, title, startDate...
  1. 对照 Plan.javainterface Plan 看字段是否一致

任务 6:再跟一条「写操作」链路 --- 删除计划(30 分钟)

前端:

341:345:D:\mes\service-front\src\apis\manage.ts 复制代码
export const delPlanApi = (id: number): Res<OperateRes> =>
  ajax({
    url: `plan/delete/${id}`,
    method: 'delete'
  })

Plan.vue 里:

75:78:D:\mes\service-front\src\views\sr\Plan.vue 复制代码
            <el-popconfirm v-if="isSys" title="删除后不可恢复,确定删除吗" @confirm="operate(delPlanApi, item.id)">
              <template #reference>
                <div class="c-primary cur-p ml10">删除</div>

Java:

124:130:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\workbench\controller\PlanController.java 复制代码
    @ApiOperation("删除实施计划")
    @DeleteMapping("/delete/{id}")
    @PreAuthorize("hasRole('sys')")
    ...
    public OperationInfo<Object> delPlan(@PathVariable Integer id) {
        return planService.deletePlan(id);
    }

统一返回 OperationInfo

13:19:D:\mes\enmo_support\src\main\java\com\enmo\enmo_support\common\result\OperationInfo.java 复制代码
public class OperationInfo<M> {

    private String operateCode;
    private String operateMessage;
    private String operateCallBackUrl;
    private Boolean success;
    private M operateCallBackObj;

≈ 前端 OperateRes{ success, operateMessage }

读 / 写 对照:

操作 HTTP 前端 API Java 注解 返回
查列表 GET getPlanListApi @GetMapping PageInfo<Plan>
删除 DELETE delPlanApi @DeleteMapping OperationInfo
保存 POST savePlanApi @PostMapping + @RequestBody OperationInfo

任务 7:了解巡检模块(30 分钟,只建立概念)

巡检是唯一走 Python 的模块,Day 1 知道存在即可。

复制代码
reportGroup.vue
  → apis/inspection.ts → getReportDetailMenuApi
  → Java BethuneAnalysisController
  → Feign BethuneAnalysisApi
  → Python group_preview.py

前端 inspection 接口示例:

typescript 复制代码
// apis/inspection.ts(结构示意)
export const getReportDetailMenuApi = (data = {}) =>
  ajax({
    url: 'bethune/viewReportDetailMenu',
    method: 'post',
    data: data
  })

仍走 /esapi/,但 Java 层会用 Feign 再调 Python。

Day 1 只需记住:

  • 巡检前端:views/inspection/ + apis/inspection.ts
  • 巡检 Java:bethune/controller/BethuneAnalysisController.java
  • 分析逻辑在 Python 项目,第 11 周再学

晚上(19:30~21:30):总结 + 笔记

任务 8:填写学习笔记

markdown 复制代码
# Day 1 学习笔记

## 1. 项目结构
- 前端:service-front(Vue 3)
- 后端:enmo_support(Java Spring Boot,端口 8084)
- 登录:走 /api/ 代理到 8080
- 业务:走 /esapi/ 代理到 8084

## 2. 两条通道
| 用途 | proxy | 端口 |
|------|-------|------|
| 登录 | /api/ | 8080 |
| MES 业务 | /esapi/(默认) | 8084 |

## 3. Java 四层
Controller → Service → Dao → Model
对应:apis → composable → SQL → interface

## 4. 今日跟完的链路

### 登录
Login.vue → submitLoginApi → POST /api/login → token 存 Vuex

### 计划列表(重点)
Plan.vue → getPlanListApi → GET /esapi/plan/list
  → PlanController.findPlanList()
  → PlanServiceImpl.findList()
  → PlanDao.findList()
  → PlanMap.xml SQL
  → 返回 { total, list }

## 5. 注解对照
| 前端 | Java |
|------|------|
| ajax url | @GetMapping / @PostMapping |
| params | @RequestParam |
| data | @RequestBody |
| url 里的 ${id} | @PathVariable |

## 6. 疑问(Day 2 解决)
- [ ] PageInfo 和 PageListRes 怎么对应?
- [ ] @PreAuthorize 权限在哪里配置?
- [ ] MyBatis XML 怎么和 Dao 接口关联?

## 7. 明日计划
- 深入 MyBatis:读懂 PlanMap.xml 动态 SQL
- 跟一条 POST 保存链路:savePlanApi
- 开始本地跑 Java 后端
相关推荐
jeffer_liu1 小时前
Spring AI 生产级实战:模型选择
java·人工智能·spring boot·后端·spring·语言模型·ai编程
User_芊芊君子1 小时前
【JavaEE】线程入门:线程基础 + 安全机制一次讲透
java·安全·java-ee
小新1101 小时前
vue架的网站修改端口
前端·javascript·vue.js
未若君雅裁1 小时前
JMM、volatile 与 CAS:并发安全三大问题
java·开发语言
暗不需求1 小时前
从零实现一个 Vue Todos 任务清单:深入响应式编程与组合式 API
前端·vue.js·面试
hai3152475431 小时前
# 矩阵算法·算子对齐工具 v6.1 — 技术规格与使用手册
java·开发语言·驱动开发·神经网络·spring·目标检测·矩阵
超绝大帅哥1 小时前
TTFB, FP, FCP, LCP, CLS, INP,TBT, TTI性能指标
前端
用户1733598075371 小时前
纯前端 PDF 处理避坑指南:5 个线上真实问题的解决方案
前端·javascript
Csvn1 小时前
前端项目管理:需求拆解、排期与风险控制
前端