springboot,how to make #Valid working in loop nesting - spring

my controller like this
#PostMapping("/")
public Result<Boolean> save(#Validated #RequestBody Request request){
//....
}
this request entity like this
public class Request{
#Valid
Request2 re;
}
the inner request entity like this
public class Request2{
#Valid
List<Email> email;
public static class Email {
#Length(max = 255, message = "len err")
private String email;
}
}
q:how to make Request.Request2.email's #Valid working,thanks!

Related

Spring Boot Rest API handling unique constraint

I have a Spring Boot Rest API. I want to create users and set a unique constraint on their email and username. That works well so far. Here are the main classes and methods:
#Entity
#NoArgsConstructor
#Getter
#Setter
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(unique = true)
#NotNull
private String email;
#Column(unique = true)
#NotNull
private String username;
#NotNull
private String password;
public User(String email, String username, String password) {
this.email = email;
this.password = password;
this.username = username;
}
}
#Data
#NoArgsConstructor
#AllArgsConstructor
public class SignupRequest {
#NotNull
private String email;
#NotNull
private String username;
#NotNull
private String password;
}
#CrossOrigin(value = "*")
#PostMapping("/signup")
public ResponseEntity<?> signup(#Valid #RequestBody SignupRequest signupRequest) {
signupService.signup(signupRequest);
return ResponseEntity.ok().build();
}
#Service
public class SignupServiceImpl implements SignupService {
#Override
public void signup(SignupRequest signupRequest) throws MessagingException, UnsupportedEncodingException {
User user = new User();
User user = new User(signupRequest.getEmail(), signupRequest.getUsername(), signupRequest.getPassword());
user = userRepository.save(user);
}
}
#Repository
#Component
public interface UserRepository extends CrudRepository<User, Long> {}
Now, the thing is, when I send a POST request to that endpoint with a username or email that already exists, I just get the http response 500 Internal Server Error. But I want to return a different status code and some Error message indicating that the email/username already exists.
Now two questions:
How can I modify the response globally? I could surround the userRepository.save(user) method with a try catch block, but I would have to do that in all the methods where I save a user separately. Can I define something like that globally?
The userRepository.save(user) method just returns a. JdbcSQLIntegrityConstraintViolationException with a pretty verbose message. Is there a way to clearly determine WHAT exactly went wrong (unique username constraint failed, unique email constraint failed, ...)? I could check if a user with that username or email exists by writing a method in the userRepository, but that looks like a lot of unnecessary sql queries to me. Is there a better way?
To answer your first question, You can handle exception globally via spring exception handling mechanism. You could use spring ControllerAdvice. Here you can set generic error response and custom http code. Here is an example of ControllerAdvice
#ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler
{
#ExceptionHandler(UserNotFoundException.class)
public final ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException ex, WebRequest request) {
String details = ex.getLocalizedMessage();
ErrorResponse error = new ErrorResponse(ApplicationConstants.RECORD_NOT_FOUND, details);
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
#ExceptionHandler(Exception.class)
public final ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex, WebRequest request) {
String details = ex.getLocalizedMessage();
ErrorResponse error = new ErrorResponse(ApplicationConstants.SERVER_ERROR, details);
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
public class ErrorResponse
{
public ErrorResponse(String message, String details) {
super();
this.message = message;
this.details = details;
}
private String message;
private String details;
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;
}
}
Now about second question you can loop through all the cause and check unique constraint name to find out what exception violated. But better approach would be to check first and if found then throw error.

Spring boot application I can not get data from oracle database it returns [] in postman

Spring boot application I can not get data from oracle database it returns []. In postman, it returns other requests e.g home method in controller class returns correctly. also, the table created by model class the problem is getting data from the table.
Here is the postman result:
I get this in console:
Model class
#Entity // This tells Hibernate to make a table out of this class
public class Userr {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private String email;
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
//Controller Class
#RestController
public class MainController {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository userRepository;
#PostMapping(path="/add") // Map ONLY POST Requests
public #ResponseBody String addNewUser (#RequestParam String name
, #RequestParam String email) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
Userr n = new Userr();
n.setName(name);
n.setEmail(email);
userRepository.save(n);
return "Saved";
}
#GetMapping(path="/all")
public #ResponseBody Iterable<Userr> getAllUsers() {
// This returns a JSON or XML with the users
//
return userRepository.findAll();
}
#GetMapping(path="/al")
public List<Userr> printPersonInfo() {
List<Userr> list = new ArrayList<>();
userRepository.findAll().forEach(list::add);
return list;
}
#RequestMapping("/user")
public String home(){
return "PPPPPP";
}
}
//Repository Class
public interface UserRepository extends CrudRepository<Userr, Integer> {
}
Add #Repository annotation to your UserRepository. It will help with your issue.

Spring MVC Based Rest Services Validations for request body

I have Rest Controller in my application which has the code snippet like below:-
#RestController
#RequestMapping("/api/v1/user")
public class UserRestControllerV1 {
#PostMapping("")
public Response registerUser(#RequestBody #Valid final Request<UserDto> request,
final HttpServletRequest httpServletRequest,
BindingResult result){
Response response = new Response(request);
if(result.hasErrors()){
response.setData(new String("Error"));
}else {
response.setData(new String("Test"));
}
return response;
}
The Request Class:-
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Request<T> {
#JsonProperty(value = "co-relation-id")
private String coRelationID;
#NotNull(message = "The request body should be present")
private T data;
/*
..... various other fields
Getters / Setters
*/
}
The UserDto Class :-
public class UserDto {
#NotNull(message = "The username should not be null")
private String username;
#NotNull(message = "The password should not be null")
#JsonIgnore
private String password;
/*
..... various other fields
Getters / Setters
*/
}
Issue : I am having issues with my validations here. The field private T data in the request class gets validated but the fields inside T - in the case UserDto are not getting validated.
So I need to know the approach or code snippet to achieve this.
I have tried configuring the hibernate validator bean in the configuration but it is of no help in the scenario
#Valid constraint will instruct the Bean Validator to delve to the type of its applied property and validate all constraints found there.
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Request<T> {
#JsonProperty(value = "co-relation-id")
private String coRelationID;
//#NotNull(message = "The request body should be present")
#Valid
private T data;
/*
..... various other fields
Getters / Setters
*/
}

Get URL parameter for crit use Spring MVC Hibernate

I want to be list out all my users with criteria of where id = formId. The code is working but just that it list out all the users instead of being filtered by formId. Please tell me where i did wrongly. Do tell me if you need any more info to solve this!
controller
*url = http://localhost:8080/User/Panda?Id=1
#RequestMapping(value = {"/{name}?Id={id}" }, method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #PathVariable("id") Integer id) {
logger.info("Users List Page - Id = " + id);
List<User> user = service.findAllUsers(id);
model.addAttribute("users", user);
return "user/list";
}
Service
public List<User> findAllUsers(Integer id) {
return dao.findAllUsers(id);
}
DAO Class
public interface UserDao {
List<User> findAllUsers(Integer id);
}
*DAOImpl Class
#SuppressWarnings("unchecked")
public List<User> findAllUsers(Integer id) {
Criteria crit = createEntityCriteria();
crit.add(Restrictions.eq("formId",id));
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<User> users = (List<Usert>) crit.list();
return users;
}
*for createEntityCriteria() i created in another class call abstractDao and extends to it.
private final Class<T> persistentClass;
#SuppressWarnings("unchecked")
public AbstractDao(){
this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
protected Criteria createEntityCriteria(){
return getSession().createCriteria(persistentClass);
}
Class Entity
#Entity
#Table(name="USER")
public class User implements Serializable{
#NotEmpty
#Column(name="formId", nullable=false)
private Integer formId;
#NotEmpty
#Column(name="FIRST_NAME", nullable=false)
private String firstName;
#NotEmpty
#Column(name="LAST_NAME", nullable=false)
private String lastName;
public Integer getFormId() {
return formId;
}
public void setFormId(Integer formId) {
this.formId= formId;
}
...
}
value = {"/{name}?Id={id}" }
This is wrong way to extract URL param. If you want to get URL param, you should pass it to your method using #RequestParam annotation:
#RequestMapping(value = {"/{name}" }, method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #RequestParam("Id") Integer id) {
//...
}
Spring automatically pass value that you need. For example in case of ?Id=1 Spring will pass 1 to your controller
In your url /{name} is a path variable and is annotated with #PathVariable like in:
#RequestMapping(value = "/foo/bar/{name}", method = GET)
#ResponseBody
public String getBarByName(#PathVariable String name) { ... }
And ?Id=id is a request parameter and is annotated wiht #RequestParam so if we map to url like this one:
http://localhost:8080/api/foo/bar?id=100
we do it like this
#RequestMapping(value = "/foo/bar", method = GET)
#ResponseBody
public String getBarById(#RequestParam("id") Integer id) { ... }
So to combine them to map to your url:
#RequestMapping(value = {"/{name}" }, params = "id", method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #PathVariable String name, #RequestParam("id" Integer id)) { ... }

springboot exceptionhandling without controller class

How to handle exception handling in Spring Boot 1.5.4 without controller class? Currently, I have only entity & repository class as below.
Task.class: (entity)
#Entity
#Table(name = "task")
public class Task implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Length(min = 1)
private String name;
public Task() {
}
public Task(String name) {
this.name = name;
}
public Task(Long id, String name) {
this.name = name;
}
public long getId() {
return id;
}
public String getName(){
return name;
}
}
Repository.class:
public interface TaskRepository extends PagingAndSortingRepository<Task, Long> {
}
POST method: return 200 ok
http://localhost:8080/tasks
{
"name" : "test"
}
But,
{
"name" : ""
}
returns 500 , instead of 400 error.
Pls let me know, if any way to handle this exception without a controller class.
You could use a global #ExceptionHandler with the #ControllerAdvice annotation. Basically, you define which Exception to handle with #ExceptionHandler within the class with #ControllerAdvice annotation, and then you implement what you want to do when that exception is thrown.
Like this:
#ControllerAdvice(basePackageClasses = RepositoryRestExceptionHandler.class)
public class GlobalExceptionHandler {
#ExceptionHandler({ValidationException.class, JsonParseException.class})
public ResponseEntity<Map<String, String>> yourExceptionHandler(Exception e) {
Map<String, String> response = new HashMap<String, String>();
response.put("message", "Bad Request");
return new ResponseEntity<Map<String, String>>(response, HttpStatus.BAD_REQUEST);
}
}
See also: http://www.ekiras.com/2016/02/how-to-do-exception-handling-in-springboot-rest-application.html

Resources