I am trying to post a request to my service, but it's not working. I am getting 400 Bad Request. I have GET requests that are working perfectly in the same controller.
Here is the method:
#RequestMapping(value = "/assign", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public Form5398Obj arriveTrip(#PathVariable String siteId,
#RequestBody ErrorMsg anError) throws Exception {
System.out.println(anError.toString());
}
The ErrorMessage java class is as follows:
public class ErrorMsg {
private String code;
private String msg;
private String request;
public ErrorMsg(String code, String msg, String request)
{
this.code = code;
this.msg = msg;
this.request = request;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getRequest() {
return request;
}
public void setRequest(String request) {
this.request = request;
}
}
I did not configure anything else. What else do I need to do to get it to work? I am using JavaConfig, do I need to add any bean declarations?
I am sending:
with Content-Type: application/json
{
"code" : "101",
"msg" : "Hello Test",
"request" : "1"
}
I believe you need a no-argument constructor for ErrorMsg so that Jackson can instantiate an object to populate for the incoming request. Otherwise it would not know how the parameters in your 3 parameter constructor should be populated.
Try adding the following
public ErrorMsg() {
}
Related
In my Spring Boot app, I implemented a global exception handler class as shown below:
#RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#Override
#ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
protected ResponseEntity<Object> handleMethodArgumentNotValid() {
// code omitted for brevity
return ResponseEntity.unprocessableEntity().body(errorResponse);
}
// other type of exceptions
}
And in my Controller, I return ResponseEntity<ApiResponse> as shown below:
#GetMapping("/categories/{id}")
public ResponseEntity<ApiResponse<CategoryResponse>> findById(#PathVariable long id){
final CategoryResponse response = categoryService.findById(id);
return ResponseEntity.ok(
new ApiResponse<>(
Instant.now(clock).toEpochMilli(), Constants.SUCCESS, response));
}
Here is my ApiResponse class:
#Data
#AllArgsConstructor
public class ApiResponse<T> {
private Long timestamp;
private final String message;
private final T data;
public ApiResponse(Long timestamp, String message) {
this.timestamp = timestamp;
this.message = message;
this.data = null;
}
}
My problem is that; when there is an error, I cannot catch it on Controller and GlobalExceptionHandler directly return error in ResponseEntity<Object> type. When I send requests via Postman, I get the error message, but when I implemented a frontend app, I realized that this format is different than return type when there is no error.
So, I think I should manage the exception as well in the Controller and return the same type data to frontend so that the return value can easily be manipulated. How should I solve this problem? I do not want to use try-catch and do not move my business logic to the Controller. Instead, maybe I should change return type of ResponseEntity<Object> in the exception handler to a similar one in the Controller. Or may need to return exception to the Controller. What should I do?
Update: I had already implemented a custom exception class:
public class ElementAlreadyExistsException extends RuntimeException {
public ElementAlreadyExistsException() {
super();
}
public ElementAlreadyExistsException(String message) {
super(message);
}
public ElementAlreadyExistsException(String message, Throwable cause) {
super(message, cause);
}
}
And use it in my `GlobalExceptionHandler` as shown below:
#ExceptionHandler(ElementAlreadyExistsException.class)
#ResponseStatus(HttpStatus.CONFLICT)
public ResponseEntity<Object> handleElementAlreadyExistsException(ElementAlreadyExistsException ex, WebRequest request) {
return buildErrorResponse(ex, HttpStatus.CONFLICT, request);
}
And the errors are build as shown below:
private ResponseEntity<Object> buildErrorResponse(Exception ex,
HttpStatus httpStatus,
WebRequest request) {
ErrorResponse errorResponse = new ErrorResponse(httpStatus.value(), message);
return ResponseEntity.status(httpStatus).body(errorResponse);
}
And here is the response class that I use for exception:
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ErrorResponse {
private final int status;
private final String message;
private String stackTrace;
private List<ValidationError> errors;
#Data
private static class ValidationError {
private final String field;
private final String message;
}
public void addValidationError(String field, String message) {
if (Objects.isNull(errors)) {
errors = new ArrayList<>();
}
errors.add(new ValidationError(field, message));
}
}
I have this code, where I send an object to the API:
validateLogin(user:User):Observable<string>{
console.log(JSON.stringify(user));
return this.http.post<string>(`http://localhost:8080/login/login`, user).pipe(
map((resp)=>{
return this.repareString(JSON.stringify(resp));
})
)
}
I don't see anything wrong, but Spring Boot says "required request parameter 'user' for method parameter type String is not present". I've also tried sending it as a JSON object but it says the same. I believe that this is caused by the code in angular, that's why I post it here.
#RestController
#RequestMapping("/login")
public class LoginController {
#PostMapping("/login")
public static String login(#RequestParam String user) throws Exception{
System.out.println(user);
Login l = new ObjectMapper().readValue(user, Login.class);
if(l.checkUser().equals("ok")){
if(l.checkPassword().equals("ok")){
return "logged";
} else {
return l.checkPassword();
}
}
return l.checkUser();
}
}
And the Login class:
public class Login extends Database{
public String email;
public String pass;
public Statement stm;
public Login(String email, String pass) throws Exception{
this.email = email;
this.pass = pass;
this.stm = (Statement) this.con.createStatement();
}
I have tried sending it as a JSON string and I've also tried sending the object properties individually as various params.
Change your controller like this:
#RestController
#RequestMapping("/login")
public class LoginController {
#PostMapping("/login")
public static String login(#RequestBody Login login) throws Exception{
System.out.println(login);
if(login.checkUser().equals("ok")){
if(login.checkPassword().equals("ok")){
return "logged";
} else {
return login.checkPassword();
}
}
return login.checkUser();
}
}
I have to retuen the message "Data Added" in the api in ResponseBody
Create a api while enters student data
/newStudent
Request Body:
{
"name":"Shubham",
"rollno":22,
"studentid":1
}
Response:
{
"status":"OK",
"message":"Data Added"
}
#RequestMapping("/studentdata")
#ResponseBody
#ResponseStatus(HttpStatus.OK )
You can create a custom response class that looks like this:
class CustomResponse {
private String status;
private String message;
// Constructor/Getters/Setters
}
Then in your controller return ResponseEntity for example:
CustomResponse response = new CustomResponse("OK", "Data Added");
return ResponseEntity.ok(response); // the ok will return HTTP Status 200
Or if you want another HttpStatus, then you can use for example:
return new ResponseEntity<>(response, HttpStatus.CREATED);
^^^^^^^^^^^^^^^^^^
First of all you should create a Response class which will hold status code and your custom message like the following class :
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Response {
private String statusCode;
private String statusMsg;
}
So in your controller where you post the object use ResponseEntity which can allow you to customize HTTP response methods. For example:
#Autowired
private StudentRepository studentRepository;
#PostMapping("/newStudent")
public ResponseEntity<Response> saveEmployee(#RequestBody Student
student){
studentRepository.save(student);
Response response = new Response();
response.setStatusCode("200");
response.setStatusMsg("Your message");
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
This is how to return custom object in response.
router.post("/newStudent", async (req, res) => {
const { name, rollNo, studentId } = req.data;
// POST data to DB
const result = await AddStudentDataToDB({ name, rollNo, studentId });
res.status(200).json({
status: 'ok',
message: 'Data Added'
});
});
import org.json.simple.JSONObject;
#ResponseBody
#RequestMapping(value = "/studentdata", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public String message(#RequestBody String transaction) {
String response = "";
JSONObject obj = new JSONObject();
obj.put("status", "OK");
obj.put("message", "Data Added");
response = obj.toJSONString();
return response;
}
It worked for me like this in Response class:
public class Response {
private String statusCode;
private String statusMsg;
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getStatusMsg() {
return statusMsg;
}
public void setStatusMsg(String statusMsg) {
this.statusMsg = statusMsg;
}
}
In controller:
#PostMapping("/newStudent")
public ResponseEntity<Response> saveStudent(#RequestBody Student student) {
Student save = service.save(student);
Response response = new Response();
response.setStatusCode("200");
response.setStatusMsg("Data Added");
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
This question already has answers here:
Spring Boot #autowired does not work, classes in different package
(13 answers)
Closed 4 years ago.
I have a very simple Rest Controller only for test and its not working..
I'm using spring boot and postman for client-side.
my rest controller:
#RestController
#RequestMapping("system")
public class LoginController {
public static CouponSystemResponse csRes = new CouponSystemResponse();
#RequestMapping(value = "login", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public CouponSystemResponse login(#RequestParam(value = "username") String username,
#RequestParam(value = "password") String password, #RequestParam(value = "type") String type) {
csRes.setMessage("You have successfully logged in");
csRes.setStatus("OK");
return csRes;
CouponSystemResponse:
#Component
public class CouponSystemResponse {
private String status = "";
private String message = "";
public CouponSystemResponse() {
}
public CouponSystemResponse(String status, String message) {
super();
this.status = status;
this.message = message;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public String toString() {
return "CouponSystemResponse [status=" + status + ", message=" + message + "]";
}
postman output:
postman output
url: http://localhost:8080/system/login?username=admin&password=1234&type=ADMIN
Can't figure what the problem could be. Appreciate any help.
Update: I add picture of main app+structure:
main app
All your components are in subpackages of package com.orel.couponsystem, but your #SpringBootApplication annotated CouponWebApplication class is in package com.orel.t.couponsystem.config, which means that none of your components are auto-scanned.
Standard solution: Move class CouponWebApplication out to the base package:
package com.orel.couponsystem;
Alternate solution: Explicitly name the base package:
#SpringBootApplication(scanBasePackages = "com.orel.couponsystem")
I'm trying to validate an email that I receive from the post request body but it's doesn't work !
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public String requestFoo(#RequestBody #Email String email) {
return email;
}
When I send a request with a string that doesn't respect the email regex the function is executed and I receive a 200 status code.
Even do I add the #Valid annotation the result is always the same.
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public String testValidation(#Valid #RequestBody #Email String email) {
return email;
}
Start with Spring 3.2 #RequestBody method argument may be followed by Errors object, hence allowing handling of validation errors in the same #RequestMapping :
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public ResponseEntity<String> testValidation(#Valid #RequestBody #Email String email, Errors errors) {
if (errors.hasErrors()) {
return ResponseEntity.badRequest().body(ValidationErrorBuilder.fromBindingErrors(errors));
}
return email;
}
And create a custom validator :
public class ValidationErrorBuilder {
public static ValidationError fromBindingErrors(Errors errors) {
ValidationError error = new ValidationError("Validation failed. " + errors.getErrorCount() + " error(s)");
for (ObjectError objectError : errors.getAllErrors()) {
error.addValidationError(objectError.getDefaultMessage());
}
return error;
}
}