Spring Boot + Vue 前后端接口交互全流程详解

一、前后端交互架构概览

Spring Boot + Vue 前后端接口交互全流程详解_第1张图片

二、Spring Boot 后端接口实现

2.1 基础REST控制器

@RestController
@RequestMapping("/api/users")
@CrossOrigin // 处理跨域,生产环境应配置具体域名
public class UserController {
    
    @Autowired
    private UserService userService;

    // 获取用户列表
    @GetMapping
    public ResponseEntity> getUsers(
            @RequestParam(required = false) String name) {
        List users = userService.findUsers(name);
        return ResponseEntity.ok(users);
    }

    // 获取单个用户
    @GetMapping("/{id}")
    public ResponseEntity getUser(@PathVariable Long id) {
        UserDTO user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }

    // 创建用户
    @PostMapping
    public ResponseEntity createUser(
            @Valid @RequestBody UserCreateRequest request) {
        UserDTO newUser = userService.createUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(newUser);
    }

    // 更新用户
    @PutMapping("/{id}")
    public ResponseEntity updateUser(
            @PathVariable Long id,
            @Valid @RequestBody UserUpdateRequest request) {
        UserDTO updatedUser = userService.updateUser(id, request);
        return ResponseEntity.ok(updatedUser);
    }

    // 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

2.2 DTO设计示例

用户创建请求DTO

@Data
public class UserCreateRequest {
    @NotBlank(message = "用户名不能为空")
    @Size(max = 50, message = "用户名最长50个字符")
    private String username;

    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度6-20位")
    private String password;

    @Email(message = "邮箱格式不正确")
    private String email;

    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;
}

用户响应DTO

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserDTO {
    private Long id;
    private String username;
    private String email;
    private String phone;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
}

2.3 全局异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 处理验证异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity handleValidationException(
            MethodArgumentNotValidException ex) {
        List errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.toList());
        
        ErrorResponse response = new ErrorResponse(
                "VALIDATION_FAILED", 
                "参数验证失败", 
                errors);
        
        return ResponseEntity.badRequest().body(response);
    }

    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity handleBusinessException(
            BusinessException ex) {
        ErrorResponse response = new ErrorResponse(
                ex.getCode(), 
                ex.getMessage(), 
                null);
        return ResponseEntity.status(ex.getStatus()).body(response);
    }
}

三、Vue 前端接口调用

3.1 Axios 封装

// src/utils/request.js
import axios from 'axios'
import { Message } from 'element-ui'
import store from '@/store'
import router from '@/router'

// 创建axios实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 10000
})

// 请求拦截器
service.interceptors.request.use(
  config => {
    // 添加token
    if (store.getters.token) {
      config.headers['Authorization'] = 'Bearer ' + store.getters.token
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  response => {
    const res = response.data
    
    // 业务错误处理
    if (res.code && res.code !== 200) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })
      
      // 特定状态码处理
      if (res.code === 401) {
        // 跳转登录
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    // HTTP错误处理
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

3.2 API模块化封装

// src/api/user.js
import request from '@/utils/request'

// 获取用户列表
export function getUsers(params) {
  return request({
    url: '/api/users',
    method: 'get',
    params
  })
}

// 获取用户详情
export function getUser(id) {
  return request({
    url: `/api/users/${id}`,
    method: 'get'
  })
}

// 创建用户
export function createUser(data) {
  return request({
    url: '/api/users',
    method: 'post',
    data
  })
}

// 更新用户
export function updateUser(id, data) {
  return request({
    url: `/api/users/${id}`,
    method: 'put',
    data
  })
}

// 删除用户
export function deleteUser(id) {
  return request({
    url: `/api/users/${id}`,
    method: 'delete'
  })
}

3.3 Vue组件中调用示例



四、接口交互关键点详解

4.1 请求参数传递方式

参数类型 前端传递方式 后端接收方式
URL路径参数 /users/123 @PathVariable Long id
URL查询参数 /users?name=John&age=20 @RequestParam String name
请求体JSON参数 {name:"John",age:20} @RequestBody UserDTO user
表单参数 FormData对象 @ModelAttribute UserForm form
请求头参数 headers: {Authorization: ...} @RequestHeader String token

4.2 跨域解决方案

Spring Boot 配置类

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://localhost:8080", "https://yourdomain.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

4.3 文件上传处理

后端接收

@PostMapping("/upload")
public ResponseEntity uploadFile(
        @RequestParam("file") MultipartFile file) {
    if (file.isEmpty()) {
        throw new BusinessException("文件不能为空");
    }
    
    String fileName = fileStorageService.storeFile(file);
    return ResponseEntity.ok(fileName);
}

前端上传

// 使用FormData上传文件
const formData = new FormData()
formData.append('file', file)

uploadFile(formData).then(response => {
  // 处理响应
})

五、接口安全增强

5.1 JWT认证实现

Spring Security配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .addFilter(new JwtAuthenticationFilter(authenticationManager()))
            .addFilter(new JwtAuthorizationFilter(authenticationManager()))
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

Vue前端处理

// 登录示例
login({ username, password }).then(response => {
  const { token } = response.data
  commit('SET_TOKEN', token)
  localStorage.setItem('token', token)
  // 设置axios默认携带token
  axios.defaults.headers.common['Authorization'] = `Bearer ${token}`
})

5.2 接口限流防护

@RestController
@RequestMapping("/api/products")
public class ProductController {
    
    @RateLimiter(value = 10, key = "'product_list'") // 10次/秒
    @GetMapping
    public List listProducts() {
        return productService.findAll();
    }
}

六、接口文档生成

6.1 Swagger集成

Spring Boot配置

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(apiInfo());
    }
    
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("电商系统API文档")
                .description("前后端接口定义")
                .version("1.0")
                .build();
    }
}

6.2 接口注释示例

@Api(tags = "用户管理")
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @ApiOperation("获取用户列表")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "name", value = "用户名", paramType = "query")
    })
    @GetMapping
    public ResponseEntity> getUsers(String name) {
        // ...
    }
}

七、性能优化建议

7.1 接口缓存策略

@Cacheable(value = "users", key = "#id")
@GetMapping("/{id}")
public UserDTO getUser(@PathVariable Long id) {
    return userService.getUserById(id);
}

7.2 分页查询优化

后端实现

@GetMapping
public PageResult getUsers(
        @RequestParam(defaultValue = "1") int page,
        @RequestParam(defaultValue = "10") int size) {
    Pageable pageable = PageRequest.of(page - 1, size);
    Page userPage = userService.findUsers(pageable);
    return new PageResult<>(userPage.getContent(), userPage.getTotalElements());
}

前端调用

getUsers({ page: this.currentPage, size: this.pageSize }).then(response => {
  this.userList = response.data.list
  this.total = response.data.total
})

八、常见问题解决方案

8.1 日期时间处理

后端配置

# application.yml
spring:
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss

前端处理

import moment from 'moment'

// 格式化日期
moment(user.createTime).format('YYYY-MM-DD HH:mm:ss')

8.2 大数字精度丢失

后端处理

@JsonSerialize(using = ToStringSerializer.class)
private Long id;

8.3 接口版本管理

@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 {
    // v1版本接口
}

@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 {
    // v2版本接口
}

通过以上方案,Spring Boot和Vue可以实现高效、安全的前后端接口交互。实际开发中应根据项目需求选择合适的传参方式、安全策略和性能优化方案。

你可能感兴趣的:(spring,boot,vue.js,交互)