如何创建接收指定JSON的Spring Boot微服务满足约束实现接口
Spring Boot 微服务实现分步指南
全程不用搞复杂配置,新手按步骤搭就能跑通:
第一步:搭项目骨架
直接从Spring官方初始化工具生成项目,选这几个必备依赖就行:
- Spring Web:支撑REST接口对外提供服务
- Spring Data JPA:处理数据存储逻辑,不用手写基础SQL
- H2 Database:内存数据库,本地调试不用额外装MySQL,启动就能用
- Validation:做参数合法性校验
- Lombok(可选):自动生成get/set方法,少写样板代码
项目生成后直接启动,确认8080端口能正常跑起来不报错就算第一步完成。
第二步:定义核心数据结构
对应你给出的JSON结构,存数据时要额外加自增主键id,注意给totalCount加上范围校验规则:
@Entity @Data public class IpRecord { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 存储时自动生成的记录id private String type; private String value; private String firstSeen; @Min(0) @Max(100) // 直接用注解限制取值范围,框架自动拦截非法值 private Integer totalCount; }
注意:不要直接用这个实体类接前端请求参数,单独写个字段完全一致的
RecordRequestDTO类接参,避免被恶意传参篡改id。
第三步:实现日期格式转换逻辑
这部分是需求核心,不要用Spring默认的单格式日期解析,自己写个工具类实现多格式兼容+统一转ISO 8601:
- 把常用的日期格式(比如
yyyy-MM-dd HH:mm:ss.SSS、yyyy/MM/dd、yyyyMMdd、yyyy-MM-dd'T'HH:mm:ss等)都放到候选格式列表里 - 接收到
firstSeen参数后,循环用所有候选格式尝试解析,只要解析成功就转成UTC时区的ISO 8601标准格式字符串 - 所有格式都解析失败时直接抛出参数非法异常,后续统一返回错误响应
参考实现代码:
public class DateConvertUtil { private static final List<DateTimeFormatter> CANDIDATE_FORMATS = Arrays.asList( DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"), DateTimeFormatter.ofPattern("yyyy/MM/dd"), DateTimeFormatter.ofPattern("yyyyMMdd"), DateTimeFormatter.ISO_LOCAL_DATE_TIME ); private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_OFFSET_DATE_TIME; public static String convertToIso8601(String dateStr) { for (DateTimeFormatter format : CANDIDATE_FORMATS) { try { LocalDateTime parsedTime = LocalDateTime.parse(dateStr, format); return parsedTime.atOffset(ZoneOffset.UTC).format(ISO_FORMATTER); } catch (Exception ignored) {} } throw new IllegalArgumentException("传入日期格式非法,无法解析"); } }
第四步:写数据访问层
直接继承JPA提供的基础Repository接口,不用自己写实现,框架会自动按方法名生成查询逻辑:
public interface RecordRepository extends JpaRepository<IpRecord, Long> { // 自动实现按value字段匹配查询的逻辑 List<IpRecord> findAllByValue(String value); }
本地调试可以在配置文件加两行配置开启H2控制台,启动后访问
/h2-console就能直接看到存进去的数据,排查问题很方便:spring.datasource.url=jdbc:h2:mem:testdb spring.h2.console.enabled=true
第五步:实现对外接口
一共两个接口,按RESTful规范写就行:
- 新增记录接口:用POST方法,路径
/api/records
逻辑:接收到合法请求参数后,调用日期转换工具把firstSeen转成标准ISO格式,调用Repository存数据,返回带自动生成id的完整记录 - 查询记录接口:用GET方法,路径
/api/records
逻辑:接收请求参数里的value值,调用Repository查询匹配的所有记录返回即可
参考Controller代码:
@RestController @RequestMapping("/api/records") @Validated public class RecordController { @Autowired private RecordRepository recordRepository; @PostMapping public ResponseEntity<IpRecord> addRecord(@Valid @RequestBody RecordRequest request) { IpRecord record = new IpRecord(); record.setType(request.getType()); record.setValue(request.getValue()); record.setFirstSeen(DateConvertUtil.convertToIso8601(request.getFirstSeen())); record.setTotalCount(request.getTotalCount()); IpRecord savedRecord = recordRepository.save(record); return ResponseEntity.ok(savedRecord); } @GetMapping public ResponseEntity<List<IpRecord>> queryByValue(@RequestParam String value) { return ResponseEntity.ok(recordRepository.findAllByValue(value)); } }
第六步:加全局异常处理
写个全局异常拦截类,把参数校验失败、日期解析失败的异常统一拦截,返回清晰的错误信息,不要把后台堆栈抛给前端:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler({ConstraintViolationException.class, IllegalArgumentException.class}) public ResponseEntity<Map<String, Object>> handleBadRequest(Exception e) { Map<String, Object> resp = new HashMap<>(); resp.put("code", 400); resp.put("msg", e.getMessage()); return ResponseEntity.badRequest().body(resp); } }
上线前必测场景
写完跑起来后把这几个场景测一遍,确保符合需求:
- 传
totalCount=-1或者totalCount=101,接口返回400错误 - 传不同格式的
firstSeen参数(比如2020/07/10、20200710),存储后的值都是统一的ISO 8601格式 - 传乱码字符串作为
firstSeen,接口返回400日期非法错误 - 新增记录后传对应
value查询,能查到刚新增的记录,返回的id是服务端自动生成的 - 传不存在的
value查询,返回空列表即可
内容的提问来源于stack exchange,提问作者bella
相关产品推荐
相关产品推荐

