Spring boot教程-实施用于 RESTful 服务的验证
实施用于 RESTful 服务的验证
验证是所有服务中的常见需求。我们将讨论 Java 验证 API,以在我们的 bean 文件中添加验证。当我们收到创建用户的请求时,我们应该验证其内容。如果无效,我们应该返回适当的响应。
让我们看看如何验证请求。
步骤 1: 打开 UserResource.java 文件。
步骤 2: 添加 @Valid 注释。这是 Javax 验证 API。其默认类路径是 spring-boot-starter-web。
UserResource.java:
package cn.javatiku.server.main.user;
import java.net.URI;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
@RestController
public class UserResource
{
@Autowired
private UserDaoService service;
@GetMapping("/users")
public List<User> retriveAllUsers()
{
return service.findAll();
}
//retrieves a specific user detail
@GetMapping("/users/{id}")
public User retriveUser(@PathVariable int id)
{
User user= service.findOne(id);
if(user==null)
//runtime exception
throw new UserNotFoundException("id: "+ id);
return user;
}
//method that delete a user resource
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable int id)
{
User user= service.deleteById(id);
if(user==null)
//runtime exception
throw new UserNotFoundException("id: "+ id);
}
//method that posts a new user detail and returns the status of the user resource
@PostMapping("/users")
public ResponseEntity<Object> createUser(@Valid @RequestBody User user)
{
User sevedUser=service.save(user);
URI location=ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(sevedUser.getId()).toUri();
return ResponseEntity.created(location).build();
}
}
现在我们将在 User 类中的 name 和 date of birth 上添加验证。假设名称至少应有五个字符,出生日期应该在过去而不是现在。
步骤 3: 打开 User.java 文件。
步骤 4: 在 name 变量上方添加 @Size(min=5) 注释。
步骤 5: 在 dob 变量上方添加 @Past 注释。
User.java:
package cn.javatiku.server.main.user;
import java.util.Date;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;
public class User
{
private Integer id;
@Size(min=5)
private String name;
@Past
private Date dob;
//default constructor
protected User()
{
}
public User(Integer id, String name, Date dob)
{
super();
this.id = id;
this.name = name;
this.dob = dob;
}
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public Date getDob()
{
return dob;
}
public void setDob(Date dob)
{
this.dob = dob;
}
@Override
public String toString()
{
//return "User [id=" + id + ", name=" + name + ", dob=" + dob + "]";
return String.format("User [id=%s, name=%s, dob=%s]", id, name, dob);
}
}
步骤 5: 打开 Rest 客户端 Postman,发送一个具有新用户名称 Tony k 的 POST 请求。它返回 Status: 201 Created。
现在我们发送另一个 POST 请求。但是名称应该少于五个字符。它返回 Status: 400 Bad Request。
当我们创建 RESTful 服务时,我们需要考虑消费者如何知道出了什么问题。为了解决这个问题,我们将添加一个方法 handleMethodArgumentNotValid()
,该方法在 ResponseEntityExceptionHandler 类中定义。这是当发生错误请求时触发的方法。
protected ResponseEntity<Object> handleMethodArgumentNotValid( MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
{
return handleExceptionInternal(ex, null, headers, status, request);
}
步骤 6: 将上述方法复制并粘贴到 CustomizedResponseEntityExceptionHandler.java 文件中。
步骤 7: 添加注释 @Override,覆盖该方法。
CustomizedResponseEntityExceptionHandler.java:
package cn.javatiku.server.main;
import java.util.Date;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import cn.javatiku.server.main.exception.ExceptionResponse;
import cn.javatiku.server.main.user.UserNotFoundException;
//defining exception handling for all the exceptions
@ControllerAdvice
@RestController
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler
{
@ExceptionHandler(Exception.class)
//override method of ResponseEntityExceptionHandler class
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request)
{
//creating exception response structure
ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
//returning exception structure and specific status
return new ResponseEntity(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(UserNotFoundException.class)
//override method of ResponseEntityExceptionHandler class
public final ResponseEntity<Object> handleUserNotFoundExceptions(UserNotFoundException ex, WebRequest request)
{
//creating exception response structure
ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
//returning exception structure and specific status
return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
{
ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.getMessage(), ex.getBindingResult().toString());
//returning exception structure and specific status
return new ResponseEntity(exceptionResponse, HttpStatus.BAD_REQUEST);
}
}
步骤 8: 现在,我们通过 Postman 发送 POST 请求。它返回带有消息 Validation failed for argument 和其他详细信息的异常结构。
用户很难理解这个消息。因此,我们现在将自定义消息更改为字符串 Validation Failed,而不是获取消息。
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
{
ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), "Validation Failed", ex.getBindingResult().toString());
//returning exception structure and specific status
return new ResponseEntity(exceptionResponse, HttpStatus.BAD_REQUEST);
}
步骤 9: 再次发送 POST 请求。它返回我们自定义的更具体的异常消息。
这可能对消费者有用。现在,我们再次自定义异常,使其更加错误特定。
步骤 10: 打开 User.java 文件,在 @Size 注释中添加属性 message="Name should have at least 5 characters"。
@Size(min=5, message="Name should have at least 5 characters")
步骤 11: 再次,发送 POST 请求。它返回我们指定的更具体异常。
我们还可以通过遵循 BindingResult 接口来进一步自定义异常。验证类别有多种异常消息。在 validation-api-2.0.1.Final.jar 中定义了以下验证类别。