SpringBoot+Vue 前后端接口交互的項(xiàng)目實(shí)踐
一、前后端交互架構(gòu)概覽
二、Spring Boot 后端接口實(shí)現(xiàn)
2.1 基礎(chǔ)REST控制器
@RestController @RequestMapping("/api/users") @CrossOrigin // 處理跨域,生產(chǎn)環(huán)境應(yīng)配置具體域名 public class UserController { @Autowired private UserService userService; // 獲取用戶列表 @GetMapping public ResponseEntity<List<UserDTO>> getUsers( @RequestParam(required = false) String name) { List<UserDTO> users = userService.findUsers(name); return ResponseEntity.ok(users); } // 獲取單個(gè)用戶 @GetMapping("/{id}") public ResponseEntity<UserDTO> getUser(@PathVariable Long id) { UserDTO user = userService.getUserById(id); return ResponseEntity.ok(user); } // 創(chuàng)建用戶 @PostMapping public ResponseEntity<UserDTO> createUser( @Valid @RequestBody UserCreateRequest request) { UserDTO newUser = userService.createUser(request); return ResponseEntity.status(HttpStatus.CREATED).body(newUser); } // 更新用戶 @PutMapping("/{id}") public ResponseEntity<UserDTO> updateUser( @PathVariable Long id, @Valid @RequestBody UserUpdateRequest request) { UserDTO updatedUser = userService.updateUser(id, request); return ResponseEntity.ok(updatedUser); } // 刪除用戶 @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.deleteUser(id); return ResponseEntity.noContent().build(); } }
2.2 DTO設(shè)計(jì)示例
用戶創(chuàng)建請(qǐng)求DTO:
@Data public class UserCreateRequest { @NotBlank(message = "用戶名不能為空") @Size(max = 50, message = "用戶名最長(zhǎng)50個(gè)字符") private String username; @NotBlank(message = "密碼不能為空") @Size(min = 6, max = 20, message = "密碼長(zhǎng)度6-20位") private String password; @Email(message = "郵箱格式不正確") private String email; @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手機(jī)號(hào)格式不正確") private String phone; }
用戶響應(yīng)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 { // 處理驗(yàn)證異常 @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidationException( MethodArgumentNotValidException ex) { List<String> errors = ex.getBindingResult() .getFieldErrors() .stream() .map(error -> error.getField() + ": " + error.getDefaultMessage()) .collect(Collectors.toList()); ErrorResponse response = new ErrorResponse( "VALIDATION_FAILED", "參數(shù)驗(yàn)證失敗", errors); return ResponseEntity.badRequest().body(response); } // 處理業(yè)務(wù)異常 @ExceptionHandler(BusinessException.class) public ResponseEntity<ErrorResponse> handleBusinessException( BusinessException ex) { ErrorResponse response = new ErrorResponse( ex.getCode(), ex.getMessage(), null); return ResponseEntity.status(ex.getStatus()).body(response); } }
三、Vue 前端接口調(diào)用
3.1 Axios 封裝
// src/utils/request.js import axios from 'axios' import { Message } from 'element-ui' import store from '@/store' import router from '@/router' // 創(chuàng)建axios實(shí)例 const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }) // 請(qǐng)求攔截器 service.interceptors.request.use( config => { // 添加token if (store.getters.token) { config.headers['Authorization'] = 'Bearer ' + store.getters.token } return config }, error => { return Promise.reject(error) } ) // 響應(yīng)攔截器 service.interceptors.response.use( response => { const res = response.data // 業(yè)務(wù)錯(cuò)誤處理 if (res.code && res.code !== 200) { Message({ message: res.message || 'Error', type: 'error', duration: 5 * 1000 }) // 特定狀態(tài)碼處理 if (res.code === 401) { // 跳轉(zhuǎn)登錄 } return Promise.reject(new Error(res.message || 'Error')) } else { return res } }, error => { // HTTP錯(cuò)誤處理 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' }) } // 創(chuàng)建用戶 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組件中調(diào)用示例
<template> <div> <el-table :data="userList"> <!-- 表格內(nèi)容 --> </el-table> <el-dialog :visible.sync="dialogVisible"> <el-form :model="userForm" :rules="rules" ref="userForm"> <!-- 表單內(nèi)容 --> </el-form> </el-dialog> </div> </template> <script> import { getUsers, createUser } from '@/api/user' export default { data() { return { userList: [], dialogVisible: false, userForm: { username: '', password: '', email: '', phone: '' }, rules: { username: [ { required: true, message: '請(qǐng)輸入用戶名', trigger: 'blur' }, { max: 50, message: '長(zhǎng)度不超過(guò)50個(gè)字符', trigger: 'blur' } ], // 其他驗(yàn)證規(guī)則... } } }, created() { this.fetchUsers() }, methods: { // 獲取用戶列表 async fetchUsers() { try { const { data } = await getUsers({ name: this.searchName }) this.userList = data } catch (error) { console.error('獲取用戶列表失敗:', error) } }, // 提交表單 submitForm() { this.$refs.userForm.validate(async valid => { if (valid) { try { await createUser(this.userForm) this.$message.success('創(chuàng)建成功') this.dialogVisible = false this.fetchUsers() // 刷新列表 } catch (error) { console.error('創(chuàng)建用戶失敗:', error) } } }) } } } </script>
四、接口交互關(guān)鍵點(diǎn)詳解
4.1 請(qǐng)求參數(shù)傳遞方式
參數(shù)類(lèi)型 | 前端傳遞方式 | 后端接收方式 |
---|---|---|
URL路徑參數(shù) | /users/123 | @PathVariable Long id |
URL查詢參數(shù) | /users?name=John&age=20 | @RequestParam String name |
請(qǐng)求體JSON參數(shù) | {name:"John",age:20} | @RequestBody UserDTO user |
表單參數(shù) | FormData對(duì)象 | @ModelAttribute UserForm form |
請(qǐng)求頭參數(shù) | headers: {Authorization: ...} | @RequestHeader String token |
4.2 跨域解決方案
Spring Boot 配置類(lèi):
@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<String> 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 => { // 處理響應(yīng) })
五、接口安全增強(qiáng)
5.1 JWT認(rèn)證實(shí)現(xiàn)
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) // 設(shè)置axios默認(rèn)攜帶token axios.defaults.headers.common['Authorization'] = `Bearer ${token}` })
5.2 接口限流防護(hù)
@RestController @RequestMapping("/api/products") public class ProductController { @RateLimiter(value = 10, key = "'product_list'") // 10次/秒 @GetMapping public List<Product> 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("電商系統(tǒng)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<List<UserDTO>> getUsers(String name) { // ... } }
七、性能優(yōu)化建議
7.1 接口緩存策略
@Cacheable(value = "users", key = "#id") @GetMapping("/{id}") public UserDTO getUser(@PathVariable Long id) { return userService.getUserById(id); }
7.2 分頁(yè)查詢優(yōu)化
后端實(shí)現(xiàn):
@GetMapping public PageResult<UserDTO> getUsers( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size) { Pageable pageable = PageRequest.of(page - 1, size); Page<UserDTO> userPage = userService.findUsers(pageable); return new PageResult<>(userPage.getContent(), userPage.getTotalElements()); }
前端調(diào)用:
getUsers({ page: this.currentPage, size: this.pageSize }).then(response => { this.userList = response.data.list this.total = response.data.total })
八、常見(jiàn)問(wèn)題解決方案
8.1 日期時(shí)間處理
后端配置:
# 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 大數(shù)字精度丟失
后端處理:
@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版本接口 }
通過(guò)以上方案,Spring Boot和Vue可以實(shí)現(xiàn)高效、安全的前后端接口交互。實(shí)際開(kāi)發(fā)中應(yīng)根據(jù)項(xiàng)目需求選擇合適的傳參方式、安全策略和性能優(yōu)化方案。
到此這篇關(guān)于SpringBoot+Vue 前后端接口交互的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)SpringBoot Vue 前后端接口交互內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java兩整數(shù)相除向上取整的方式詳解(Math.ceil())
在調(diào)外部接口獲取列表數(shù)據(jù)時(shí),需要判斷是否已經(jīng)取完了所有的值,因此需要用到向上取整,下面這篇文章主要給大家介紹了關(guān)于Java兩整數(shù)相除向上取整的相關(guān)資料,需要的朋友可以參考下2022-06-06SpringBoot接口中如何直接返回圖片數(shù)據(jù)
這篇文章主要介紹了SpringBoot接口中如何直接返回圖片數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03javax.persistence中@Column定義字段類(lèi)型方式
這篇文章主要介紹了javax.persistence中@Column定義字段類(lèi)型方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11IDEA在Maven項(xiàng)目中使用本地jar包的方法
我們?cè)谀玫脚f項(xiàng)目的時(shí)候,經(jīng)常會(huì)遇到一種情況,就是這個(gè)項(xiàng)目的maven中依賴了一個(gè)本地的jar包,這種情況就需要引入這個(gè)jar包,所以本文給大家介紹了IDEA在Maven項(xiàng)目中使用本地jar包的方法,需要的朋友可以參考下2024-04-04如何使用SpEL表達(dá)式實(shí)現(xiàn)動(dòng)態(tài)分表查詢
這篇文章主要介紹了如何使用SpEL表達(dá)式實(shí)現(xiàn)動(dòng)態(tài)分表查詢,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Java如何接收XML格式參數(shù)并轉(zhuǎn)換為JSON
在 Java 應(yīng)用程序中,處理 XML 數(shù)據(jù)并將其轉(zhuǎn)換為 JSON 格式是很常見(jiàn)的任務(wù),這篇文章為大家整理了一下具體的實(shí)現(xiàn)方法,希望對(duì)大家有所幫助2025-03-03Java數(shù)據(jù)結(jié)構(gòu)貪心算法的實(shí)現(xiàn)
本文主要介紹了Java數(shù)據(jù)結(jié)構(gòu)貪心算法的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2007-03-03