API接口日期时间字段怎么传?从RFC 3339、ISO 8601到时间戳的实战选型指南
2026/4/23 18:03:17
随着互联网技术的普及和餐饮文化的多元化发展,美食交流与宣传逐渐从线下转向线上。传统的美食分享方式受限于地域和时间,难以满足用户即时交流、信息获取的需求。JavaWeb技术栈因其成熟性和跨平台特性,成为开发此类系统的常见选择。SpringBoot框架简化了JavaWeb应用的配置和部署流程,能够快速构建高性能、可扩展的系统。
通过SpringBoot构建的美食交流系统,兼具技术可行性和社会需求,为美食爱好者与行业从业者提供了高效的信息交互平台。
SpringBoot基于JavaWeb的美食交流宣传系统通常采用分层架构设计,结合前后端技术实现功能模块。以下为典型技术栈组成:
注:实际技术选型需根据项目规模、团队熟悉度和性能需求调整。例如,小型项目可简化消息队列和微服务设计,直接使用SpringBoot单体架构。
以下是一个基于Spring Boot的美食交流宣传系统的核心代码示例,涵盖主要功能模块的实现:
// 用户实体 @Entity @Table(name = "user") @Data public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String password; private String email; private String avatar; @CreationTimestamp private LocalDateTime createTime; } // 美食文章实体 @Entity @Table(name = "article") @Data public class Article { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; private String content; private String coverImage; @ManyToOne private User author; @CreationTimestamp private LocalDateTime createTime; }// 用户Repository public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); } // 文章Repository public interface ArticleRepository extends JpaRepository<Article, Long> { List<Article> findByTitleContaining(String keyword); List<Article> findByAuthorId(Long authorId); }@Service @RequiredArgsConstructor public class ArticleService { private final ArticleRepository articleRepository; public Article createArticle(Article article, User author) { article.setAuthor(author); return articleRepository.save(article); } public Page<Article> getArticles(Pageable pageable) { return articleRepository.findAll(pageable); } } @Service @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; public User register(User user) { user.setPassword(passwordEncoder.encode(user.getPassword())); return userRepository.save(user); } }@RestController @RequestMapping("/api/articles") @RequiredArgsConstructor public class ArticleController { private final ArticleService articleService; @GetMapping public ResponseEntity<Page<Article>> getAllArticles( @PageableDefault(size = 10) Pageable pageable) { return ResponseEntity.ok(articleService.getArticles(pageable)); } @PostMapping public ResponseEntity<Article> createArticle( @RequestBody Article article, @AuthenticationPrincipal User user) { return ResponseEntity.ok(articleService.createArticle(article, user)); } } @RestController @RequestMapping("/api/auth") @RequiredArgsConstructor public class AuthController { private final UserService userService; @PostMapping("/register") public ResponseEntity<User> register(@Valid @RequestBody User user) { return ResponseEntity.ok(userService.register(user)); } }@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final UserDetailsService userDetailsService; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .addFilter(new JwtAuthorizationFilter(authenticationManager())); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }@Service public class FileStorageService { private final Path root = Paths.get("uploads"); public void init() { try { Files.createDirectories(root); } catch (IOException e) { throw new RuntimeException("Could not initialize folder for upload!"); } } public String store(MultipartFile file) { String filename = UUID.randomUUID() + "_" + file.getOriginalFilename(); try { Files.copy(file.getInputStream(), this.root.resolve(filename)); return filename; } catch (Exception e) { throw new RuntimeException("Could not store the file. Error: " + e.getMessage()); } } }@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception ex) { ErrorResponse error = new ErrorResponse( HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage()); return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidationException( MethodArgumentNotValidException ex) { String message = ex.getBindingResult() .getFieldErrors() .stream() .map(FieldError::getDefaultMessage) .collect(Collectors.joining(", ")); ErrorResponse error = new ErrorResponse( HttpStatus.BAD_REQUEST.value(), message); return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); } }@Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager("articles", "users"); } }以上代码构成了一个基础的美食交流系统核心框架,可根据实际需求扩展更多功能如评论系统、点赞收藏、食谱分类等功能模块。系统采用RESTful API设计,前后端分离架构,包含用户认证、文章管理、文件上传等核心功能。
实体关系模型(ER图)核心表结构:
用户表(user)
user_id(主键)、username、password(加密存储)、email、avatar(头像路径)、role(用户/管理员)、create_timeusername和email需唯一索引。美食表(food)
food_id(主键)、name、description、image_url、category(分类如川菜、西餐)、user_id(外键关联用户表)、create_timecategory和user_id建立普通索引。评论表(comment)
comment_id(主键)、content、user_id(外键)、food_id(外键)、create_timefood_id和user_id联合查询优化。收藏表(favorite)
favorite_id(主键)、user_id(外键)、food_id(外键)、create_timeuser_id和food_id防止重复收藏。点赞表(like)
like_id(主键)、user_id(外键)、food_id(外键)、create_timeuser_id和food_id。SQL示例:
CREATE TABLE `user` ( `user_id` INT AUTO_INCREMENT PRIMARY KEY, `username` VARCHAR(50) UNIQUE NOT NULL, `password` VARCHAR(100) NOT NULL, `email` VARCHAR(100) UNIQUE NOT NULL, `avatar` VARCHAR(255) DEFAULT 'default.png', `role` ENUM('user', 'admin') DEFAULT 'user', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP );单元测试(JUnit + Mockito)
用户服务测试
@Test(expected = DuplicateUsernameException.class) public void testRegisterDuplicateUsername() { when(userRepository.findByUsername("test")).thenReturn(new User()); userService.register("test", "123456", "test@example.com"); }美食服务测试
@Test(expected = PermissionDeniedException.class) public void testAddFoodWithoutAdminRole() { User user = new User(); user.setRole("user"); foodService.addFood(user, "火锅", "描述", "image.jpg", "川菜"); }接口测试(Postman)
用户登录接口
POST /api/login{"username":"test", "password":"123456"}token字段。美食列表分页接口
GET /api/food?page=1&size=10&category=川菜性能测试(JMeter)
安全测试
' OR '1'='1,验证是否返回错误或过滤结果。<script>alert(1)</script>,验证是否被转义。自动化测试(Selenium)
WebDriver driver = new ChromeDriver(); driver.get("http://localhost:8080/register"); driver.findElement(By.id("username")).sendKeys("testuser"); // 其他操作...通过分层测试确保系统功能完整性和稳定性。