首页
复制
搜索
前进
后退
重载网页
和我当邻居
给我留言吧
首页
壁纸
影院
统计
关于
友链
留言
Search
1
面向对象核心
28 阅读
2
Java枚举类
26 阅读
3
Lambda表达式与Stream
23 阅读
4
Java常用API与类
20 阅读
5
集合框架主要集合类及其用法
20 阅读
随笔
JAVA
Mysql
JavaWeb
Tools
登录
Search
标签搜索
集合框架
fnm
枚举
数组
基础语法
面向对象
Comparator
Comparable
Cloneable
内部类
普通成员内部类
普通局部内部类
静态成员内部类
静态成员代码块
Throwable
异常类
密封类
代码块
普通成员代码块
Mathlei
阿简
累计撰写
34
篇文章
累计收到
0
条评论
首页
栏目
随笔
JAVA
Mysql
JavaWeb
Tools
页面
壁纸
影院
统计
关于
友链
留言
搜索到
1
篇与
的结果
2024-09-10
RESTful 规范的 CRUD实践
RESTful 规范的 CRUD 操作符合 REST 架构风格的 API,能够使服务具有良好的可扩展性和松耦合性。RESTful API 的核心概念包括资源、URI(统一资源标识符)、无状态性,以及使用标准的 HTTP 方法来对资源进行操作。HTTP 方法在 RESTful API 中用于定义资源操作:GET 用于获取资源数据,不会对服务器端的数据造成任何修改。示例:GET /api/users/1 用于获取 ID 为 1 的用户信息。POST 用于在服务器端创建新资源,通常会在成功创建后返回新资源的 URI。示例:POST /api/users 用于创建一个新用户。PUT 用于更新资源,通常用于更新整个资源或根据请求内容对资源进行修改。示例:PUT /api/users/1 用于更新 ID 为 1 的用户信息。PATCH 用于部分更新资源,区别于 PUT,PATCH 只更新提供的字段。示例:PATCH /api/users/1 用于更新 ID 为 1 的用户的部分信息。DELETE 用于删除资源。示例:DELETE /api/users/1 用于删除 ID 为 1 的用户。状态码在 RESTful API 中用于表示请求结果的状态:200 OK 表示请求成功,返回期望的响应数据。201 Created 表示成功创建资源,返回新资源的 URI。204 No Content 表示请求成功,但不返回任何内容,通常用于删除操作。400 Bad Request 表示客户端请求无效,通常由于请求参数有误。401 Unauthorized 表示请求未经授权,通常因为身份验证失败。403 Forbidden 表示请求被服务器拒绝,通常因为权限不足。404 Not Found 表示请求的资源不存在。500 Internal Server Error 表示服务器内部错误。RESTful API 的 URI 设计应清晰明了、符合层次结构,并使用名词表示资源。通常使用名词的复数形式表示资源集合,例如 /api/users 表示用户资源。路径设计中避免使用动词,如 /getUser,而应通过 HTTP 方法表达操作类型。版本控制可以通过在 URI 中添加版本号(如 /api/v1/users),或者通过请求头指定在 RESTful API 的版本控制中,使用 URI 版本控制或请求头版本控制是较为常见的两种策略:URI 版本控制:直接在 URI 中添加版本号,例如 /api/v1/users。这种方式简单直观,易于理解,但会导致 URI 更加冗长,并且如果版本众多,管理起来会比较复杂。请求头版本控制:通过自定义请求头来指定版本号,例如 Accept: application/vnd.example.v1+json。这种方式更加灵活,URI 不会随着版本的增加而变得混乱,但客户端需要明确设置请求头。在实际应用中,RESTful API 通常需要实现基本的 CRUD 操作,并遵循最佳实践以确保 API 的易用性、可维护性和安全性。实现 CRUD 操作的一个基本示例使用 Spring Boot 框架。以下是如何在 Spring Boot 中创建一个完整的 RESTful CRUD 操作示例。创建实体类 User 表示用户资源:@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增策略 private Long id; @NotBlank(message = "Name is mandatory") // 校验字段不为空 private String name; @Email(message = "Email should be valid") // 校验邮箱格式 private String email; // Getters 和 Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }在数据访问层,创建一个接口 UserRepository,继承自 JpaRepository,用于基本的 CRUD 操作:public interface UserRepository extends JpaRepository<User, Long> { // 自定义查询方法:按名称查找用户 List<User> findByName(String name); }服务层的实现用于处理业务逻辑。UserService 提供了用户的增删改查操作:@Service public class UserService { @Autowired private UserRepository userRepository; // 创建用户 public User createUser(User user) { return userRepository.save(user); } // 根据ID获取用户 public User getUserById(Long id) { return userRepository.findById(id).orElse(null); } // 获取所有用户 public List<User> getAllUsers() { return userRepository.findAll(); } // 更新用户 public User updateUser(Long id, User userDetails) { User user = getUserById(id); if (user != null) { user.setName(userDetails.getName()); user.setEmail(userDetails.getEmail()); return userRepository.save(user); } return null; } // 删除用户 public void deleteUser(Long id) { userRepository.deleteById(id); } }控制器层 UserController 负责处理 HTTP 请求并返回相应的响应数据:@RestController @RequestMapping("/api/users") public class UserController { @Autowired private UserService userService; @PostMapping // 创建用户 public ResponseEntity<User> createUser(@RequestBody User user) { User createdUser = userService.createUser(user); return new ResponseEntity<>(createdUser, HttpStatus.CREATED); } @GetMapping("/{id}") // 根据ID获取用户 public ResponseEntity<User> getUserById(@PathVariable Long id) { User user = userService.getUserById(id); if (user != null) { return new ResponseEntity<>(user, HttpStatus.OK); } return new ResponseEntity<>(HttpStatus.NOT_FOUND); } @GetMapping // 获取所有用户 public ResponseEntity<List<User>> getAllUsers() { List<User> users = userService.getAllUsers(); return new ResponseEntity<>(users, HttpStatus.OK); } @PutMapping("/{id}") // 更新用户 public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User userDetails) { User updatedUser = userService.updateUser(id, userDetails); if (updatedUser != null) { return new ResponseEntity<>(updatedUser, HttpStatus.OK); } return new ResponseEntity<>(HttpStatus.NOT_FOUND); } @DeleteMapping("/{id}") // 删除用户 public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.deleteUser(id); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } }RESTful API 设计的最佳实践包括:使用 HTTPS 确保数据传输的安全性。实现身份验证和授权,例如使用 JWT(JSON Web Token)或 OAuth 2.0,确保只有合法的用户能够访问资源。使用标准化的 API 文档工具(如 Swagger)生成文档,使 API 更加易于理解和使用。提供分页、过滤和排序功能,以提升数据查询的灵活性和性能。遵循 HATEOAS(超媒体作为应用状态的引擎)原则,为客户端提供导航链接,帮助客户端更容易地探索和使用 API。拦截器(Interceptor)拦截器在 Web 应用中是一种特殊的过滤器,用于在请求到达控制器之前或返回响应之前执行某些逻辑。拦截器通常用于日志记录、权限验证、数据预处理、异常处理等场景。在 Spring MVC 中,可以通过实现 HandlerInterceptor 接口来定义自定义拦截器。拦截器通常有三个方法:preHandle:在请求到达控制器之前调用。可以用于身份验证、权限检查、日志记录等操作。如果该方法返回 false,请求将不会继续向下传递。postHandle:在控制器执行完逻辑之后,但在视图渲染之前调用。可以用于修改视图或向模型中添加通用数据。afterCompletion:在请求完全处理完毕后调用,通常用于清理资源、记录日志等操作。在 Spring Boot 中,拦截器的配置可以通过创建一个配置类并实现 WebMvcConfigurer 接口来完成:@Component public class LoggingInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Request URI: " + request.getRequestURI()); return true; // 继续处理请求 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Post Handle method is Calling"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception { System.out.println("Request and Response is completed"); } }通过创建一个配置类并将拦截器注册到 Spring 的拦截器链中:@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private LoggingInterceptor loggingInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loggingInterceptor).addPathPatterns("/**"); } }使用 @Validated 注解可以结合拦截器实现数据校验。例如,在拦截器中可以结合方法参数中的注解进行校验,确保请求数据的合法性。异常处理全局异常处理可以确保应用程序在出现异常时返回统一的错误响应,从而提高应用的健壮性和用户体验。在 Spring Boot 中,可以使用 @ControllerAdvice 和 @ExceptionHandler 注解实现全局异常处理。通过定义一个全局异常处理类,并使用 @ControllerAdvice 注解标识,该类会捕获并处理应用程序中的所有异常:@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<?> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) { ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND); } @ExceptionHandler(Exception.class) public ResponseEntity<?> handleGlobalException(Exception ex, WebRequest request) { ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR); } }自定义异常类 ResourceNotFoundException 用于表示资源未找到的情况:public class ResourceNotFoundException extends RuntimeException { public ResourceNotFoundException(String message) { super(message); } }通过这种方式,应用程序的异常处理逻辑集中在一个地方,便于管理和维护。异常处理程序根据捕获的异常类型,返回适当的 HTTP 状态码和错误信息。使用 ResponseEntity 可以灵活地构建标准化的错误响应对象。在实际应用中,为了提高 API 的可用性和可维护性,统一的错误响应格式是一个良好的实践。通常会包含以下信息:timestamp:错误发生的时间。message:错误的具体信息。details:错误的详细描述,例如请求的 URI。示例的错误响应对象 ErrorDetails 类如下:public class ErrorDetails { private Date timestamp; private String message; private String details; public ErrorDetails(Date timestamp, String message, String details) { super(); this.timestamp = timestamp; this.message = message; this.details = details; } // Getters 和 Setters public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getDetails() { return details; } public void setDetails(String details) { this.details = details; } }通过全局异常处理器,所有未捕获的异常都会被自动处理,并返回标准化的错误响应。这样可以确保 API 对外暴露的接口稳定,同时为客户端提供一致的错误信息格式,方便调试和错误处理。自定义校验器在实际应用中,有时我们需要对输入数据进行复杂的校验,而这些校验可能无法通过简单的注解(如 @NotNull、@Email 等)来实现。此时可以通过实现自定义校验器来完成。创建一个自定义校验注解,如 @ValidPassword,用于验证用户密码的复杂性(例如必须包含大写字母、小写字母、数字和特殊字符):定义注解 ValidPassword:@Constraint(validatedBy = PasswordValidator.class) // 绑定自定义校验器 @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ValidPassword { String message() default "Invalid password"; // 默认错误信息 Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }实现自定义校验逻辑:public class PasswordValidator implements ConstraintValidator<ValidPassword, String> { private Pattern pattern; private Matcher matcher; private static final String PASSWORD_PATTERN = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$"; @Override public void initialize(ValidPassword constraintAnnotation) { pattern = Pattern.compile(PASSWORD_PATTERN); // 初始化密码匹配正则 } @Override public boolean isValid(String password, ConstraintValidatorContext context) { if (password == null) { return false; // 密码不能为空 } matcher = pattern.matcher(password); return matcher.matches(); // 返回匹配结果 } }在实体类中使用自定义校验注解:public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotBlank(message = "Name is mandatory") private String name; @Email(message = "Email should be valid") private String email; @ValidPassword // 使用自定义的密码校验注解 private String password; // Getters 和 Setters }当客户端请求中包含无效密码时,自定义校验器会触发相应的错误,并在响应中返回错误信息。通过自定义校验器,可以灵活地满足各种复杂的校验需求。数据校验与错误消息提示使用 @Validated 注解结合 BindingResult 对象,可以在控制器中实现更加细粒度的错误处理逻辑。示例中,我们在创建用户时应用这些技术:@PostMapping("/users") public ResponseEntity<?> createUser(@Validated @RequestBody User user, BindingResult result) { if (result.hasErrors()) { // 检查校验结果是否有错误 List<String> errors = result.getAllErrors().stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) // 提取所有错误消息 .collect(Collectors.toList()); return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); // 返回错误响应 } User createdUser = userService.createUser(user); return new ResponseEntity<>(createdUser, HttpStatus.CREATED); }通过 BindingResult 对象,可以获取所有的校验错误,并返回给客户端。这样,客户端可以根据具体的错误消息提示用户输入的错误信息。CORS(跨域资源共享)跨域资源共享(CORS)是一种浏览器安全机制,用于防止不受信任的域对资源的未经授权的访问。RESTful API 通常需要支持 CORS,以允许来自不同域的客户端(如 Web 应用程序)与服务器通信。在 Spring Boot 中,可以使用 @CrossOrigin 注解启用 CORS。例如,在控制器方法上添加此注解:@CrossOrigin(origins = "http://example.com") // 允许来自指定来源的跨域请求 @GetMapping("/users") public ResponseEntity<List<User>> getAllUsers() { List<User> users = userService.getAllUsers(); return new ResponseEntity<>(users, HttpStatus.OK); }或者在全局配置中启用 CORS 支持:@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 允许跨域的路径 .allowedOrigins("http://example.com") // 允许的来源 .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的 HTTP 方法 .allowCredentials(true); // 是否允许发送凭证(如 cookies) } }通过正确配置 CORS,客户端可以安全地访问 RESTful API,同时确保数据和用户隐私的安全性。
2024年09月10日
2 阅读
0 评论
0 点赞