技术栈:

SpringBoot,MySQL, MybatisPlus, Knife4J,Lombok

项目初始化

使用Mybatis代码生成器生成实体类,mapper接口&xml文件等;

构建统一返回结果Result类,返回的提示信息统一封装在枚举类中。

项目初始化结构:

这里生成的mapper接口不带@mapper,并且,产生的是swagger2的@Api注解,这就需要我们额外操作。下面是生成代码器的代码

package cn.amebob.cv01;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;

public class CodeGenerator {
    public static void main(String[] args) {
        // 1. 数据库配置
        String url = "jdbc:mysql://localhost:3306/test_db?serverTimezone=GMT%2B8";
        String username = "root";
        String password = "root";

        FastAutoGenerator.create(url, username, password)
                .globalConfig(builder -> {
                    builder.author("bob")

                            .enableSwagger()
                            .outputDir(System.getProperty("user.dir") + "/src/main/java");
                })
                .packageConfig(builder -> {
                    builder.parent("cn.amebob.cv01")
                            .pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/mapper"));
                })
                .strategyConfig(builder -> {
                    builder.addInclude("Experience", "Profile", "Project", "ProjectTag", "Tag", "User")
                            .entityBuilder()
                            .enableLombok()
                            .idType(IdType.AUTO)
                            .enableTableFieldAnnotation()
                            .controllerBuilder()
                            .enableRestStyle();
                })
                .templateEngine(new FreemarkerTemplateEngine())
                .execute();

        System.out.println("代码生成成功!");
    }
}

这里Result类可以使用@Builder,方便我们链式调用;

return Result.success(user).setMessage("查询个人资料成功");

Result,由于需要返回多次,非单例等问题,不交予Spring容器管理,这里采用静态方式创建Result对象,是静态工厂方法。

package cn.amebob.cv01.common;

import lombok.Builder;
import lombok.Data;

import java.io.Serializable;
@Builder
@Data
public class Result<T> implements Serializable {
    private int code;
    private String message;
    private T data;
    private long timestamp;

    public Result() {
        this.timestamp = System.currentTimeMillis();
    }

    // 成功返回 - 无数据
    public static <T> Result<T> success() {
        return success(null);
    }

    // 成功返回 - 有数据
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(ResultCode.SUCCESS.getCode());
        result.setMessage(ResultCode.SUCCESS.getMessage());
        result.setData(data);
        return result;
    }

    // 失败返回 - 默认信息
    public static <T> Result<T> fail() {
        return fail(ResultCode.INTERNAL_SERVER_ERROR.getMessage());
    }

    // 失败返回 - 自定义信息
    public static <T> Result<T> fail(String message) {
        Result<T> result = new Result<>();
        result.setCode(ResultCode.INTERNAL_SERVER_ERROR.getCode());
        result.setMessage(message);
        return result;
    }
}

遇到的问题

  • 浏览器网络面板(Network)看到状态码是 200,但控制台(Console)却报错 CORS。

现象解释:浏览器已经把请求发出去了,后端也处理完并返回了数据,但浏览器发现响应头里没有准许跨域的标识,于是出于安全考虑,把已经到手的数据“没收”了,并抛出一个跨域错误给你的 JS 代码。

解决方法:前端跨域设置正确,但是request.js的baseURL设置为了` http://localhost:8080` 这是后端地址,这样前端就直接跳过了跨域代理。

上线后的跨域问题:

既然 Proxy 只管开发环境,项目上线后通常有两种方案:

  1. Nginx 转发(最常用):在服务器上配置 Nginx,让 Nginx 扮演和 Proxy 同样的角色。

  2. 后端开启 CORS:在 SpringBoot 中配置 WebMvcConfigurer 允许跨域。这样前端可以直接请求 http://api.yourdomain.com 而不需要任何代理。

  • 父组件向子组件传输信息,子组件未展示

起初以为是pinia的问题,在使用调试工具后,确认pinia中数据更新。提供js、模版代码给ai,得到答案,js中获取ref对象的属性值需要使用.value

// 如果直接解构 const { profileInfo } = profileStore; 会失去响应式
const { profileInfo, loading } = storeToRefs(profileStore);

const info = profileInfo.value; //正确
const info = profileInfo;//错误

//铺数据时,模板中可以省去.value

<div v-if="profileInfo">
        <h1>你好我是 <span class="highlight">{{ profileInfo.name }}</span></h1>
        <h2>{{ profileInfo.jobTitle }}</h2>
        <p>{{ profileInfo.bio }}</p>

        <SocialLinks :links="socialData" />
</div>
  • 更改Vue组建数据请求时,导致其它页面空白