快学快用系列:一文学会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

AI 辅助安卓逆向:TRAE+JADX-AI-MCP 插件实战

前言:随着大模型(LLM)的爆发,编程辅助工具层出不穷。但在安卓逆向领域,如何将 AI 的理解能力直接嵌入到我们熟悉的工具链中?今天介绍的 JADX-AI-MCP 就是这样一个革命性的插件,它是 Zin MCP Suite 的一部分,通过 MCP(Model Context Protocol)协议,将 JADX 与 Claude/Cursor 等 AI 助手无缝连接,实现了“反编译 -> AI 代码审计 -> 自动重命名/分析”的闭环工作流。 🛠️ 什么是 JADX-AI-MCP? JADX-AI-MCP 是 JADX 的一个插件,它配合 JADX-MCP-SERVER(

快速搭建个人AI知识库教程(超详细+实战)从零入门到精通,一篇全掌握!

本文详细介绍了一款名为PandaWiki的开源个人知识库工具,它结合传统文档管理与AI检索增强生成技术。文章演示了如何在Linux系统上通过Docker一键部署PandaWiki,配置各类模型,以及从飞书等平台导入文档创建个人AI知识库。该工具支持离线文件上传、AI生成摘要、文档分类管理等功能,并提供多种问答机器人接入方式,是个人知识管理和AI学习的理想解决方案。 最近有点忙,拖更比较久了,大家见谅… 今天我们一起来聊聊知识库。 当下,RAG 技术已经非常成熟了,市面上的各种 AI 知识库产品也很丰富。 在这个 AI 时代的浪潮下,如果你还用传统的笔记软件来管理个人知识,就有点显得 Out 了。 不过,想要选到一款称心如意的知识库工具,似乎也不是那么简单。 首先是数据隐私上的考虑,虽然现在很多在线 AI 平台似乎都支持了知识库上传的能力,但有些 “私密” 的知识我们可能不想上传到 “云端”。 另外,虽然有很多大厂直接提供了非常全面的私有化部署方案,但是动辄几万的费用让人望而却步。 那就只能从开源工具上下手了,作为个人的知识库管理工具,我希望使用一款 “小而美” 的产品,

AI 驱动游戏:鸿蒙生态的机会在哪里?

AI 驱动游戏:鸿蒙生态的机会在哪里?

子玥酱(掘金 / 知乎 / ZEEKLOG / 简书 同名) 大家好,我是子玥酱,一名长期深耕在一线的前端程序媛 👩‍💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。 我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括前端工程化、小程序、React / RN、Flutter、跨端方案, 在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。 技术方向:前端 / 跨端 / 小程序 / 移动端工程化 内容平台:掘金、知乎、ZEEKLOG、简书 创作特点:实战导向、源码拆解、少空谈多落地 文章状态:长期稳定更新,大量原创输出 我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在“API 怎么用”,而是更关注为什么这么设计、在什么场景下容易踩坑、

2026年3月大模型全景深度解析:国产登顶、百万上下文落地、Agent工业化,AI实用时代全面来临[特殊字符]

2026年3月大模型全景深度解析:国产登顶、百万上下文落地、Agent工业化,AI实用时代全面来临[特殊字符]

🔥个人主页:北极的代码(欢迎来访) 🎬作者简介:java后端学习者 ❄️个人专栏:苍穹外卖日记,SSM框架深入,JavaWeb ✨命运的结局尽可永在,不屈的挑战却不可须臾或缺! 前言: 2026年3月,全球大模型领域迎来颠覆性变革——国产模型实现全球调用量反超,百万上下文从“实验室概念”变成“工业级标配”,Agent智能体摆脱“玩具级应用”,正式进入千行百业。本文将从行业格局、核心技术、产业落地 3大维度,结合具体产品参数、技术细节和实战案例,全面拆解当前大模型最新动态,帮开发者精准把握AI时代红利(干货密集,建议收藏反复研读)。 一、行业炸点:国产大模型历史性反超,全球格局彻底重塑(附权威数据) 2026年3月,OpenRouter(全球最大AI模型调用统计平台)、斯坦福HAI研究院联合发布《全球大模型发展月报》,核心数据颠覆行业认知:中国大模型周调用量达4.69万亿Token,同比增长320%,连续两周超越美国(4.21万亿Token),全球调用量TOP10中,