快学快用系列:一文学会java后端WebApi开发

快学快用系列:一文学会java后端WebApi开发
在这里插入图片描述

文章目录

在这里插入图片描述

第一部分:Web API开发基础概念

1.1 什么是Web API

Web API(Application Programming Interface)是一种允许不同软件系统之间进行通信的接口。在Web开发中,API通常基于HTTP协议,使用RESTful架构风格,通过URL端点提供数据和服务。

Web API的核心特点:

  • 基于HTTP/HTTPS协议
  • 返回结构化数据(JSON/XML)
  • 无状态通信
  • 跨平台兼容

1.2 RESTful API设计原则

REST(Representational State Transfer)是一种软件架构风格,包含以下核心原则:

  1. 统一接口:使用标准的HTTP方法和状态码
  2. 无状态:每个请求包含所有必要信息
  3. 可缓存:响应应标记为可缓存或不可缓存
  4. 分层系统:客户端不需要知道是否连接到最终服务器
  5. 按需代码:服务器可以临时扩展功能

第二部分:开发环境搭建

2.1 环境要求

必需工具:

  • JDK 8或以上版本
  • IDE(IntelliJ IDEA/Eclipse)
  • Maven 3.6+ 或 Gradle
  • MySQL/PostgreSQL数据库

2.2 创建Spring Boot项目

使用Spring Initializr创建项目:

<!-- pom.xml --><?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.0</version><relativePath/></parent><groupId>com.example</groupId><artifactId>webapi-demo</artifactId><version>1.0.0</version><properties><java.version>11</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>

2.3 配置文件

# application.ymlserver:port:8080servlet:context-path: /api spring:datasource:url: jdbc:mysql://localhost:3306/webapi_db username: root password: password driver-class-name: com.mysql.cj.jdbc.Driver jpa:hibernate:ddl-auto: update show-sql:trueproperties:hibernate:dialect: org.hibernate.dialect.MySQL8Dialect format_sql:truelogging:level:com.example: DEBUG org.hibernate.SQL: DEBUG 

第三部分:项目架构设计

3.1 分层架构

典型的Java Web API采用分层架构:

Controller层 (API接口) ↓ Service层 (业务逻辑) ↓ Repository层 (数据访问) ↓ Model层 (数据模型) 

3.2 包结构设计

src/main/java/com/example/webapi/ ├── config/ # 配置类 ├── controller/ # 控制器 ├── service/ # 业务逻辑 ├── repository/ # 数据访问 ├── model/ # 数据模型 │ ├── entity/ # 实体类 │ ├── dto/ # 数据传输对象 │ └── vo/ # 视图对象 ├── exception/ # 异常处理 └── util/ # 工具类 

第四部分:数据模型设计

4.1 实体类设计

// User.javapackagecom.example.webapi.model.entity;importjavax.persistence.*;importjavax.validation.constraints.*;importjava.time.LocalDateTime;importjava.util.List;@Entity@Table(name ="users")publicclassUser{@Id@GeneratedValue(strategy =GenerationType.IDENTITY)privateLong id;@NotBlank(message ="用户名不能为空")@Size(min =3, max =50, message ="用户名长度必须在3-50字符之间")@Column(unique =true, nullable =false)privateString username;@Email(message ="邮箱格式不正确")@Column(unique =true, nullable =false)privateString email;@NotBlank(message ="密码不能为空")@Size(min =6, message ="密码长度至少6位")privateString password;privateString phone;@Enumerated(EnumType.STRING)privateUserStatus status =UserStatus.ACTIVE;@Column(name ="created_at")privateLocalDateTime createdAt;@Column(name ="updated_at")privateLocalDateTime updatedAt;// 构造方法publicUser(){this.createdAt =LocalDateTime.now();this.updatedAt =LocalDateTime.now();}// Getter和Setter方法// ... 省略具体实现}enumUserStatus{ ACTIVE, INACTIVE, DELETED }

4.2 DTO设计

// UserDTO.javapackagecom.example.webapi.model.dto;importjavax.validation.constraints.*;importjava.time.LocalDateTime;publicclassUserDTO{privateLong id;@NotBlank(message ="用户名不能为空")privateString username;@Email(message ="邮箱格式不正确")privateString email;privateString phone;privateLocalDateTime createdAt;// 构造方法publicUserDTO(){}// Getter和Setter// ... 省略具体实现}// CreateUserRequest.javapackagecom.example.webapi.model.dto;importjavax.validation.constraints.*;publicclassCreateUserRequest{@NotBlank(message ="用户名不能为空")@Size(min =3, max =50)privateString username;@Email@NotBlankprivateString email;@NotBlank@Size(min =6)privateString password;privateString phone;// Getter和Setter// ... 省略具体实现}

第五部分:数据访问层实现

5.1 Repository接口

// UserRepository.javapackagecom.example.webapi.repository;importcom.example.webapi.model.entity.User;importcom.example.webapi.model.entity.UserStatus;importorg.springframework.data.jpa.repository.JpaRepository;importorg.springframework.data.jpa.repository.Query;importorg.springframework.data.repository.query.Param;importorg.springframework.stereotype.Repository;importjava.util.List;importjava.util.Optional;@RepositorypublicinterfaceUserRepositoryextendsJpaRepository<User,Long>{Optional<User>findByUsername(String username);Optional<User>findByEmail(String email);List<User>findByStatus(UserStatus status);booleanexistsByUsername(String username);booleanexistsByEmail(String email);@Query("SELECT u FROM User u WHERE u.email LIKE %:email%")List<User>findByEmailContaining(@Param("email")String email);@Query("SELECT u FROM User u WHERE u.createdAt >= :startDate AND u.createdAt < :endDate")List<User>findUsersByCreateTimeRange(@Param("startDate")LocalDateTime startDate,@Param("endDate")LocalDateTime endDate);}

5.2 自定义Repository实现

// UserRepositoryCustom.javapackagecom.example.webapi.repository;importcom.example.webapi.model.entity.User;importorg.springframework.data.domain.Page;importorg.springframework.data.domain.Pageable;importjava.util.List;publicinterfaceUserRepositoryCustom{Page<User>findUsersWithPagination(String keyword,Pageable pageable);List<User>findActiveUsersWithRecentActivity();}// UserRepositoryCustomImpl.javapackagecom.example.webapi.repository;importcom.example.webapi.model.entity.User;importcom.example.webapi.model.entity.UserStatus;importorg.springframework.data.domain.Page;importorg.springframework.data.domain.PageImpl;importorg.springframework.data.domain.Pageable;importorg.springframework.stereotype.Repository;importjavax.persistence.EntityManager;importjavax.persistence.PersistenceContext;importjavax.persistence.TypedQuery;importjava.time.LocalDateTime;importjava.util.List;@RepositorypublicclassUserRepositoryCustomImplimplementsUserRepositoryCustom{@PersistenceContextprivateEntityManager entityManager;@OverridepublicPage<User>findUsersWithPagination(String keyword,Pageable pageable){String countQueryStr ="SELECT COUNT(u) FROM User u WHERE "+"(u.username LIKE :keyword OR u.email LIKE :keyword) AND u.status = 'ACTIVE'";TypedQuery<Long> countQuery = entityManager.createQuery(countQueryStr,Long.class); countQuery.setParameter("keyword","%"+ keyword +"%");Long total = countQuery.getSingleResult();String queryStr ="SELECT u FROM User u WHERE "+"(u.username LIKE :keyword OR u.email LIKE :keyword) AND u.status = 'ACTIVE' "+"ORDER BY u.createdAt DESC";TypedQuery<User> query = entityManager.createQuery(queryStr,User.class); query.setParameter("keyword","%"+ keyword +"%"); query.setFirstResult((int) pageable.getOffset()); query.setMaxResults(pageable.getPageSize());List<User> users = query.getResultList();returnnewPageImpl<>(users, pageable, total);}@OverridepublicList<User>findActiveUsersWithRecentActivity(){String queryStr ="SELECT u FROM User u WHERE u.status = 'ACTIVE' "+"AND u.updatedAt >= :recentTime";return entityManager.createQuery(queryStr,User.class).setParameter("recentTime",LocalDateTime.now().minusDays(7)).getResultList();}}

第六部分:业务逻辑层实现

6.1 Service接口设计

// UserService.javapackagecom.example.webapi.service;importcom.example.webapi.model.dto.CreateUserRequest;importcom.example.webapi.model.dto.UpdateUserRequest;importcom.example.webapi.model.dto.UserDTO;importorg.springframework.data.domain.Page;importorg.springframework.data.domain.Pageable;importjava.util.List;publicinterfaceUserService{UserDTOcreateUser(CreateUserRequest request);UserDTOgetUserById(Long id);UserDTOgetUserByUsername(String username);Page<UserDTO>getAllUsers(Pageable pageable);List<UserDTO>searchUsers(String keyword);UserDTOupdateUser(Long id,UpdateUserRequest request);voiddeleteUser(Long id);booleanexistsByUsername(String username);booleanexistsByEmail(String email);}

6.2 Service实现类

// UserServiceImpl.javapackagecom.example.webapi.service.impl;importcom.example.webapi.model.dto.CreateUserRequest;importcom.example.webapi.model.dto.UpdateUserRequest;importcom.example.webapi.model.dto.UserDTO;importcom.example.webapi.model.entity.User;importcom.example.webapi.model.entity.UserStatus;importcom.example.webapi.repository.UserRepository;importcom.example.webapi.service.UserService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.domain.Page;importorg.springframework.data.domain.Pageable;importorg.springframework.security.crypto.password.PasswordEncoder;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.util.List;importjava.util.stream.Collectors;@Service@TransactionalpublicclassUserServiceImplimplementsUserService{@AutowiredprivateUserRepository userRepository;@AutowiredprivatePasswordEncoder passwordEncoder;@OverridepublicUserDTOcreateUser(CreateUserRequest request){// 检查用户名和邮箱是否已存在if(userRepository.existsByUsername(request.getUsername())){thrownewRuntimeException("用户名已存在");}if(userRepository.existsByEmail(request.getEmail())){thrownewRuntimeException("邮箱已存在");}// 创建用户实体User user =newUser(); user.setUsername(request.getUsername()); user.setEmail(request.getEmail()); user.setPassword(passwordEncoder.encode(request.getPassword())); user.setPhone(request.getPhone()); user.setStatus(UserStatus.ACTIVE);User savedUser = userRepository.save(user);returnconvertToDTO(savedUser);}@Override@Transactional(readOnly =true)publicUserDTOgetUserById(Long id){User user = userRepository.findById(id).orElseThrow(()->newRuntimeException("用户不存在"));returnconvertToDTO(user);}@Override@Transactional(readOnly =true)publicUserDTOgetUserByUsername(String username){User user = userRepository.findByUsername(username).orElseThrow(()->newRuntimeException("用户不存在"));returnconvertToDTO(user);}@Override@Transactional(readOnly =true)publicPage<UserDTO>getAllUsers(Pageable pageable){return userRepository.findAll(pageable).map(this::convertToDTO);}@Override@Transactional(readOnly =true)publicList<UserDTO>searchUsers(String keyword){return userRepository.findByEmailContaining(keyword).stream().map(this::convertToDTO).collect(Collectors.toList());}@OverridepublicUserDTOupdateUser(Long id,UpdateUserRequest request){User user = userRepository.findById(id).orElseThrow(()->newRuntimeException("用户不存在"));// 更新用户信息if(request.getEmail()!=null&&!request.getEmail().equals(user.getEmail())){if(userRepository.existsByEmail(request.getEmail())){thrownewRuntimeException("邮箱已存在");} user.setEmail(request.getEmail());}if(request.getPhone()!=null){ user.setPhone(request.getPhone());}User updatedUser = userRepository.save(user);returnconvertToDTO(updatedUser);}@OverridepublicvoiddeleteUser(Long id){User user = userRepository.findById(id).orElseThrow(()->newRuntimeException("用户不存在")); user.setStatus(UserStatus.DELETED); userRepository.save(user);}@Override@Transactional(readOnly =true)publicbooleanexistsByUsername(String username){return userRepository.existsByUsername(username);}@Override@Transactional(readOnly =true)publicbooleanexistsByEmail(String email){return userRepository.existsByEmail(email);}// 转换实体为DTOprivateUserDTOconvertToDTO(User user){UserDTO dto =newUserDTO(); dto.setId(user.getId()); dto.setUsername(user.getUsername()); dto.setEmail(user.getEmail()); dto.setPhone(user.getPhone()); dto.setCreatedAt(user.getCreatedAt());return dto;}}

第七部分:控制器层实现

7.1 基础控制器

// UserController.javapackagecom.example.webapi.controller;importcom.example.webapi.model.dto.CreateUserRequest;importcom.example.webapi.model.dto.UpdateUserRequest;importcom.example.webapi.model.dto.UserDTO;importcom.example.webapi.service.UserService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.domain.Page;importorg.springframework.data.domain.PageRequest;importorg.springframework.data.domain.Pageable;importorg.springframework.data.domain.Sort;importorg.springframework.http.HttpStatus;importorg.springframework.http.ResponseEntity;importorg.springframework.validation.annotation.Validated;importorg.springframework.web.bind.annotation.*;importjavax.validation.Valid;importjava.util.HashMap;importjava.util.List;importjava.util.Map;@RestController@RequestMapping("/users")@ValidatedpublicclassUserController{@AutowiredprivateUserService userService;@PostMappingpublicResponseEntity<?>createUser(@Valid@RequestBodyCreateUserRequest request){try{UserDTO user = userService.createUser(request);returnResponseEntity.status(HttpStatus.CREATED).body(createSuccessResponse("用户创建成功", user));}catch(RuntimeException e){returnResponseEntity.badRequest().body(createErrorResponse(e.getMessage()));}}@GetMapping("/{id}")publicResponseEntity<?>getUserById(@PathVariableLong id){try{UserDTO user = userService.getUserById(id);returnResponseEntity.ok(createSuccessResponse("获取用户成功", user));}catch(RuntimeException e){returnResponseEntity.status(HttpStatus.NOT_FOUND).body(createErrorResponse(e.getMessage()));}}@GetMappingpublicResponseEntity<?>getAllUsers(@RequestParam(defaultValue ="0")int page,@RequestParam(defaultValue ="10")int size,@RequestParam(defaultValue ="createdAt")String sort){Pageable pageable =PageRequest.of(page, size,Sort.by(sort).descending());Page<UserDTO> users = userService.getAllUsers(pageable);Map<String,Object> response =newHashMap<>(); response.put("success",true); response.put("message","获取用户列表成功"); response.put("data", users.getContent()); response.put("currentPage", users.getNumber()); response.put("totalItems", users.getTotalElements()); response.put("totalPages", users.getTotalPages());returnResponseEntity.ok(response);}@GetMapping("/search")publicResponseEntity<?>searchUsers(@RequestParamString keyword){List<UserDTO> users = userService.searchUsers(keyword);returnResponseEntity.ok(createSuccessResponse("搜索用户成功", users));}@PutMapping("/{id}")publicResponseEntity<?>updateUser(@PathVariableLong id,@Valid@RequestBodyUpdateUserRequest request){try{UserDTO user = userService.updateUser(id, request);returnResponseEntity.ok(createSuccessResponse("用户更新成功", user));}catch(RuntimeException e){returnResponseEntity.badRequest().body(createErrorResponse(e.getMessage()));}}@DeleteMapping("/{id}")publicResponseEntity<?>deleteUser(@PathVariableLong id){try{ userService.deleteUser(id);returnResponseEntity.ok(createSuccessResponse("用户删除成功",null));}catch(RuntimeException e){returnResponseEntity.badRequest().body(createErrorResponse(e.getMessage()));}}// 工具方法:创建成功响应privateMap<String,Object>createSuccessResponse(String message,Object data){Map<String,Object> response =newHashMap<>(); response.put("success",true); response.put("message", message); response.put("data", data); response.put("timestamp",System.currentTimeMillis());return response;}// 工具方法:创建错误响应privateMap<String,Object>createErrorResponse(String message){Map<String,Object> response =newHashMap<>(); response.put("success",false); response.put("message", message); response.put("timestamp",System.currentTimeMillis());return response;}}

7.2 全局异常处理

// GlobalExceptionHandler.javapackagecom.example.webapi.exception;importorg.springframework.http.HttpStatus;importorg.springframework.http.ResponseEntity;importorg.springframework.validation.FieldError;importorg.springframework.web.bind.MethodArgumentNotValidException;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.RestControllerAdvice;importjavax.servlet.http.HttpServletRequest;importjava.util.HashMap;importjava.util.Map;@RestControllerAdvicepublicclassGlobalExceptionHandler{@ExceptionHandler(MethodArgumentNotValidException.class)publicResponseEntity<?>handleValidationExceptions(MethodArgumentNotValidException ex,HttpServletRequest request){Map<String,String> errors =newHashMap<>(); ex.getBindingResult().getAllErrors().forEach((error)->{String fieldName =((FieldError) error).getField();String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage);});Map<String,Object> response =newHashMap<>(); response.put("success",false); response.put("message","参数验证失败"); response.put("errors", errors); response.put("path", request.getRequestURI()); response.put("timestamp",System.currentTimeMillis());returnResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);}@ExceptionHandler(RuntimeException.class)publicResponseEntity<?>handleRuntimeException(RuntimeException ex,HttpServletRequest request){Map<String,Object> response =newHashMap<>(); response.put("success",false); response.put("message", ex.getMessage()); response.put("path", request.getRequestURI()); response.put("timestamp",System.currentTimeMillis());returnResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);}@ExceptionHandler(Exception.class)publicResponseEntity<?>handleGlobalException(Exception ex,HttpServletRequest request){Map<String,Object> response =newHashMap<>(); response.put("success",false); response.put("message","服务器内部错误"); response.put("path", request.getRequestURI()); response.put("timestamp",System.currentTimeMillis());returnResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);}}

第八部分:安全配置

8.1 Spring Security配置

// SecurityConfig.javapackagecom.example.webapi.config;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.http.SessionCreationPolicy;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.security.crypto.password.PasswordEncoder;importorg.springframework.security.web.SecurityFilterChain;@Configuration@EnableWebSecuritypublicclassSecurityConfig{@BeanpublicSecurityFilterChainfilterChain(HttpSecurity http)throwsException{ http .cors().and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/api/auth/**").permitAll().antMatchers("/api/users/create").permitAll().antMatchers("/api/public/**").permitAll().anyRequest().authenticated();return http.build();}@BeanpublicPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}}

8.2 JWT认证配置

// JwtUtils.javapackagecom.example.webapi.util;importio.jsonwebtoken.*;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;importjava.util.Date;@ComponentpublicclassJwtUtils{@Value("${app.jwt.secret}")privateString jwtSecret;@Value("${app.jwt.expiration}")privateint jwtExpirationMs;publicStringgenerateJwtToken(String username){returnJwts.builder().setSubject(username).setIssuedAt(newDate()).setExpiration(newDate((newDate()).getTime()+ jwtExpirationMs)).signWith(SignatureAlgorithm.HS512, jwtSecret).compact();}publicStringgetUserNameFromJwtToken(String token){returnJwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();}publicbooleanvalidateJwtToken(String authToken){try{Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);returntrue;}catch(SignatureException e){// 日志记录}catch(MalformedJwtException e){// 日志记录}catch(ExpiredJwtException e){// 日志记录}catch(UnsupportedJwtException e){// 日志记录}catch(IllegalArgumentException e){// 日志记录}returnfalse;}}

第九部分:高级特性实现

9.1 缓存配置

// CacheConfig.javapackagecom.example.webapi.config;importorg.springframework.cache.CacheManager;importorg.springframework.cache.annotation.EnableCaching;importorg.springframework.cache.concurrent.ConcurrentMapCacheManager;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.util.Arrays;@Configuration@EnableCachingpublicclassCacheConfig{@BeanpublicCacheManagercacheManager(){ConcurrentMapCacheManager cacheManager =newConcurrentMapCacheManager(); cacheManager.setCacheNames(Arrays.asList("users","products"));return cacheManager;}}// 在Service中使用缓存@ServicepublicclassUserServiceImplimplementsUserService{@Cacheable(value ="users", key ="#id")@OverridepublicUserDTOgetUserById(Long id){// 从数据库获取用户}@CacheEvict(value ="users", key ="#id")@OverridepublicUserDTOupdateUser(Long id,UpdateUserRequest request){// 更新用户}}

9.2 异步处理

// AsyncConfig.javapackagecom.example.webapi.config;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.annotation.EnableAsync;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importjava.util.concurrent.Executor;@Configuration@EnableAsyncpublicclassAsyncConfig{@Bean(name ="taskExecutor")publicExecutortaskExecutor(){ThreadPoolTaskExecutor executor =newThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(100); executor.setThreadNamePrefix("AsyncThread-"); executor.initialize();return executor;}}// 异步服务@ServicepublicclassEmailService{@Async("taskExecutor")publicvoidsendWelcomeEmail(String email,String username){// 发送邮件的逻辑try{Thread.sleep(5000);// 模拟耗时操作System.out.println("欢迎邮件已发送至: "+ email);}catch(InterruptedException e){Thread.currentThread().interrupt();}}}

第十部分:测试

10.1 单元测试

// UserServiceTest.javapackagecom.example.webapi.service;importcom.example.webapi.model.dto.CreateUserRequest;importcom.example.webapi.model.dto.UserDTO;importcom.example.webapi.model.entity.User;importcom.example.webapi.repository.UserRepository;importorg.junit.jupiter.api.BeforeEach;importorg.junit.jupiter.api.Test;importorg.junit.jupiter.api.extension.ExtendWith;importorg.mockito.InjectMocks;importorg.mockito.Mock;importorg.mockito.junit.jupiter.MockitoExtension;importorg.springframework.security.crypto.password.PasswordEncoder;importjava.util.Optional;importstaticorg.junit.jupiter.api.Assertions.*;importstaticorg.mockito.ArgumentMatchers.any;importstaticorg.mockito.Mockito.*;@ExtendWith(MockitoExtension.class)classUserServiceTest{@MockprivateUserRepository userRepository;@MockprivatePasswordEncoder passwordEncoder;@InjectMocksprivateUserServiceImpl userService;privateCreateUserRequest createUserRequest;@BeforeEachvoidsetUp(){ createUserRequest =newCreateUserRequest(); createUserRequest.setUsername("testuser"); createUserRequest.setEmail("[email protected]"); createUserRequest.setPassword("password123"); createUserRequest.setPhone("13800138000");}@TestvoidcreateUser_Success(){// 准备when(userRepository.existsByUsername("testuser")).thenReturn(false);when(userRepository.existsByEmail("[email protected]")).thenReturn(false);when(passwordEncoder.encode("password123")).thenReturn("encodedPassword");User savedUser =newUser(); savedUser.setId(1L); savedUser.setUsername("testuser"); savedUser.setEmail("[email protected]");when(userRepository.save(any(User.class))).thenReturn(savedUser);// 执行UserDTO result = userService.createUser(createUserRequest);// 验证assertNotNull(result);assertEquals(1L, result.getId());assertEquals("testuser", result.getUsername());assertEquals("[email protected]", result.getEmail());verify(userRepository,times(1)).save(any(User.class));}@TestvoidgetUserById_UserExists(){// 准备User user =newUser(); user.setId(1L); user.setUsername("testuser"); user.setEmail("[email protected]");when(userRepository.findById(1L)).thenReturn(Optional.of(user));// 执行UserDTO result = userService.getUserById(1L);// 验证assertNotNull(result);assertEquals(1L, result.getId());assertEquals("testuser", result.getUsername());}}

10.2 集成测试

// UserControllerIntegrationTest.javapackagecom.example.webapi.controller;importcom.example.webapi.model.dto.CreateUserRequest;importcom.example.webapi.repository.UserRepository;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.http.MediaType;importorg.springframework.test.web.servlet.MockMvc;importorg.springframework.transaction.annotation.Transactional;importstaticorg.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;importstaticorg.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@SpringBootTest@AutoConfigureMockMvc@TransactionalclassUserControllerIntegrationTest{@AutowiredprivateMockMvc mockMvc;@AutowiredprivateObjectMapper objectMapper;@AutowiredprivateUserRepository userRepository;@TestvoidcreateUser_ValidRequest_ReturnsCreated()throwsException{CreateUserRequest request =newCreateUserRequest(); request.setUsername("integrationtest"); request.setEmail("[email protected]"); request.setPassword("password123"); mockMvc.perform(post("/api/users").contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(request))).andExpect(status().isCreated()).andExpect(jsonPath("$.success").value(true)).andExpect(jsonPath("$.data.username").value("integrationtest"));}@TestvoidgetUserById_UserExists_ReturnsUser()throwsException{// 先创建用户CreateUserRequest request =newCreateUserRequest(); request.setUsername("testuser"); request.setEmail("[email protected]"); request.setPassword("password123");String response = mockMvc.perform(post("/api/users").contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(request))).andReturn().getResponse().getContentAsString();// 提取用户ID并查询// 这里简化处理,实际应该解析响应获取ID mockMvc.perform(get("/api/users/1")).andExpect(status().isOk()).andExpect(jsonPath("$.success").value(true));}}

第十一部分:部署与监控

11.1 Docker配置

# Dockerfile FROM openjdk:11-jre-slim WORKDIR /app COPY target/webapi-demo-1.0.0.jar app.jar RUN sh -c 'touch /app.jar' ENV EXPOSE 8080 ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ] 
# docker-compose.ymlversion:'3.8'services:webapi:build: . ports:-"8080:8080"environment:- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/webapi_db - SPRING_DATASOURCE_USERNAME=root - SPRING_DATASOURCE_PASSWORD=password depends_on:- mysql mysql:image: mysql:8.0environment:- MYSQL_ROOT_PASSWORD=password - MYSQL_DATABASE=webapi_db ports:-"3306:3306"volumes:- mysql_data:/var/lib/mysql volumes:mysql_data:

11.2 健康检查与监控

// HealthCheckController.javapackagecom.example.webapi.controller;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.actuate.health.HealthComponent;importorg.springframework.boot.actuate.health.HealthEndpoint;importorg.springframework.jdbc.core.JdbcTemplate;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.HashMap;importjava.util.Map;@RestController@RequestMapping("/health")publicclassHealthCheckController{@AutowiredprivateJdbcTemplate jdbcTemplate;@AutowiredprivateHealthEndpoint healthEndpoint;@GetMappingpublicMap<String,Object>healthCheck(){Map<String,Object> health =newHashMap<>();// 数据库健康检查try{ jdbcTemplate.execute("SELECT 1"); health.put("database","UP");}catch(Exception e){ health.put("database","DOWN");}// 系统健康检查HealthComponent systemHealth = healthEndpoint.health(); health.put("status", systemHealth.getStatus().getCode()); health.put("timestamp",System.currentTimeMillis());return health;}}

第十二部分:最佳实践与总结

12.1 API设计最佳实践

  1. 使用合适的HTTP状态码
    • 200: 成功
    • 201: 创建成功
    • 400: 客户端错误
    • 401: 未授权
    • 403: 禁止访问
    • 404: 资源不存在
    • 500: 服务器错误
  2. 统一的响应格式
{"success":true,"message":"操作成功","data":{},"timestamp":1640995200000}
  1. 版本控制
    • URL路径版本: /api/v1/users
    • 请求头版本: Accept: application/vnd.example.v1+json
  2. 分页和过滤
    • GET /api/users?page=0&size=10&sort=createdAt,desc
    • GET /api/users?name=john&email=example.com

12.2 性能优化建议

  1. 数据库优化
    • 合理使用索引
    • 避免N+1查询问题
    • 使用连接查询替代多次查询
  2. 缓存策略
    • 使用Redis进行会话存储
    • 缓存热点数据
    • 设置合理的缓存过期时间
  3. 异步处理
    • 使用消息队列处理耗时操作
    • 异步发送邮件和通知
    • 后台任务处理

12.3 安全考虑

  1. 输入验证
    • 使用Bean Validation注解
    • 防范SQL注入
    • XSS防护
  2. 认证授权
    • 使用JWT进行无状态认证
    • 基于角色的访问控制
    • API密钥管理
  3. 其他安全措施
    • HTTPS强制使用
    • 定期更新依赖
    • 安全头部配置

12.4 总结

通过本文的详细讲解,您应该已经掌握了Java后端Web API开发的全流程。从环境搭建、项目架构设计,到具体的编码实现和测试部署,我们覆盖了开发一个完整Web API项目所需的所有关键知识点。

核心要点回顾:

  • 采用分层架构,保持代码清晰和可维护性
  • 使用Spring Boot快速开发,减少配置工作
  • 实现完整的CRUD操作和业务逻辑
  • 添加适当的异常处理和日志记录
  • 编写全面的测试用例
  • 考虑安全性和性能优化

在实际项目开发中,还需要根据具体需求不断调整和优化架构设计,同时关注代码质量、团队协作和持续集成等工程实践。希望本文能为您的Java Web API开发之旅提供有力的帮助!

Read more

vs code 中内置的聊天是 GitHub Copilot Chat 吗

vs code 中内置的聊天是 GitHub Copilot Chat 吗

vs code 中内置的聊天是 GitHub Copilot Chat 吗 vs code 中内置的聊天要分情况讨论: 1. VS Code 内置的聊天(“Ask Cody”):不是 GitHub Copilot Chat VS Code 在 2023 年底(1.85 版本)引入了一个内置的聊天侧边栏,它的默认提供者是 VS Code 自己的 AI 助手 “Cody”。 * 这个功能是 VS Code 编辑器的一部分,图标通常是一个对话框气泡 💬。 * 它的目标是提供与编辑器深度集成的通用编程帮助,例如解释代码、生成代码、问答等。 * 它不一定与你的 GitHub Copilot 订阅绑定,即使你没有订阅

AI 智能编码工具:重塑开发效率的革命,从 GitHub Copilot 到国产新秀的全面解析

AI 智能编码工具:重塑开发效率的革命,从 GitHub Copilot 到国产新秀的全面解析

目录 引言 一、主流智能编码工具深度测评:从功能到实战 1. GitHub Copilot:AI 编码的 “开山鼻祖” 核心特性与实战代码 优缺点总结 2. Baidu Comate:文心大模型加持的 “国产之光” 核心特性与实战代码 优缺点总结 3. 通义灵码:阿里云的 “企业级编码助手” 核心特性与实战代码 优缺点总结 引言 作为一名拥有 8 年开发经验的程序员,我曾无数次在深夜对着屏幕反复调试重复代码,也因记不清框架语法而频繁切换浏览器查询文档。直到 2021 年 GitHub Copilot 问世,我才第一次感受到:AI 不仅能辅助编码,更能彻底改变开发模式。如今,智能编码工具已从 “尝鲜选项” 变为 “必备工具”,它们像经验丰富的结对编程伙伴,能精准补全代码、生成测试用例、

【Model】【llm38】Llama API - 示例

【Model】【llm38】Llama API - 示例

案例目标 Llama API是一个托管的Llama 2 API服务,支持函数调用功能。本案例展示了如何通过LlamaIndex集成Llama API,实现基本的文本补全、对话交互、函数调用和结构化数据提取功能。Llama API为开发者提供了一个便捷的方式来使用Llama 2模型,无需本地部署,可以直接通过API调用模型服务,大大简化了使用流程。同时,该API支持函数调用功能,使得模型能够与外部工具和服务进行交互,扩展了应用场景。 环境配置 1. 安装依赖 安装必要的依赖包: %pip install llama-index-program-openai %pip install llama-index-llms-llama-api !pip install llama-index 2. 获取API密钥 要运行此示例,您需要从Llama API官网获取API密钥。 3. 导入库并设置API密钥 导入必要的库并设置API密钥: from llama_index.llms.llama_api import LlamaAPI

llama.cpp + llama-server 的安装部署验证

飞桨AI Studio星河社区-人工智能学习与实训社区 用的是 魔塔的免费资源 不太稳定 我的Notebook · 魔搭社区 cat /etc/os-release  Ubuntu 22.04.5 LTS (Jammy Jellyfish) —— 这是一个长期支持(LTS)且完全受支持的现代 Linux 发行版,非常适合部署 llama.cpp + llama-server。Ubuntu 22.04 自带较新的 GCC(11+)、CMake(3.22+)和 Python 3.10+,无需手动升级工具链,部署过程非常顺畅。 一、安装系统依赖 sudo apt update sudo apt install -y