spring CRUD DELETE action that return viewmodel or empty body - spring

I want to write a DELETE action that return a no content body if no id error exist. If id not exist I want to redirect to the coresponding GET view.
Controller code:
#RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.GET)
public String getDeleteTodo(Model model, #PathVariable("id") String id)
{
Optional<Todo> todo = todoRepository.findById(Long.decode(id));
if (todo.isEmpty()) {
model.addAttribute("msginfo", "ctl-todo.delete.msginfo.id-not-exist");
model.addAttribute("requestedId", id);
}
else {
model.addAttribute("todo", todo.get());
}
return "v-todo-delete";
}
#RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.DELETE)
public String deleteTodo(#PathVariable String id, RedirectAttributes redirAttrs)
{
boolean exists = todoRepository.existsById(Long.decode(id));
if (exists) {
todoRepository.deleteById(Long.decode(id));
return ""; //here I want to return a no-content body response
}
else {
redirAttrs.addFlashAttribute("msginfo", "ctl-todo.delete.msginfo.id-not-exist");
redirAttrs.addFlashAttribute("requestedId", id);
return "redirect:/todo/delete" + id;
}
}
More informations about the view:
The GET view is juste a view that display the todo entity corresponding to the id. The deletion is make with a button using ajax to call the DELETE method. Then response is return as 204 with no content into the body, i redirect the user with javascript to the main page... If an id not exist in the DELETE method, I want to redirect to the GET method to show an error message.
If someone have an idea to do this.
Thanks in advance.

Try using return type as ResponseEntity with whatever response body along with a response status. Please refer below code changes:
#RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.DELETE)
public ResponseEntity deleteTodo(#PathVariable String id, RedirectAttributes redirAttrs)
{
boolean exists = todoRepository.existsById(Long.decode(id));
if (exists) {
todoRepository.deleteById(Long.decode(id));
return new ResponseEntity(HttpStatus.NO_CONTENT); //This will return No Content status
}
else {
redirAttrs.addFlashAttribute("msginfo", "ctl-todo.delete.msginfo.id-not-exist");
redirAttrs.addFlashAttribute("requestedId", id);
return new ResponseEntity( "redirect:/todo/delete" + id, HttpStatus.OK);
}
}

Final anwser for me:
#RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.DELETE)
public ResponseEntity<?> deleteTodo(#PathVariable String id, RedirectAttributes redirAttrs)
{
boolean exists = todoRepository.existsById(Long.decode(id));
if (exists) {
todoRepository.deleteById(Long.decode(id));
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
else {
redirAttrs.addFlashAttribute("msginfo", "ctl-todo.delete.msginfo.id-not-exist");
redirAttrs.addFlashAttribute("requestedId", id);
/* I use CONFLICT here to explain that the entity was possibly deleted
by another user between the moment the user give the view containing
the DELETE ajax link and the moment he click on it. */
return new ResponseEntity<String>( "redirect:/todo/delete" + id, HttpStatus.CONFLICT);
}
}
Thank you Mandar Dharurkar & Jeethesh Kotian for your help ;)

Related

Can't pass param when redirect

In my spring boot app I want to pass param errorMessage when user is admin.
snippet:
#Controller
public class UsersController {
#GetMapping("/users")
public String getAllUsers(Model model, RedirectAttributes redirectAttributes) {
logger.info("getAllUsers: model = " + model + ", redirectAttributes= " + redirectAttributes);
Set<Role> roleSet = new HashSet<>();
roleSet.add(Role.ADMIN);
adminsList = userRepository.findAllByRolesIn(roleSet);
model.addAttribute("usersList", userRepository.findAll());
model.addAttribute("adminsList", adminsList);
model.addAttribute("appName", appName);
return "users";
}
#RequestMapping("user/delete/{id}")
public String deleteUser(#PathVariable("id") int id, RedirectAttributes redirectAttributes) {
logger.info("user_id_to_delete = " + id);
Optional<User> userAdmin = adminsList.stream()
.filter(user -> user.getId() == id)
.findFirst();
if (userAdmin.isPresent() && adminsList.size() == 1) {
String errorMessage = "In system must have at least one administrator";
logger.error(errorMessage);
redirectAttributes.addAttribute("errorMessage", errorMessage);
} else {
userRepository.deleteById(id);
}
return "redirect:/users";
}
after try to delete user (method deleteUser) success call
redirectAttributes.addAttribute("errorMessage", errorMessage);
And after that success call method getAllUsers. But param redirectAttributes is empty.
Based on the api documentation
A RedirectAttributes model is empty when the method is called and is
never used unless the method returns a redirect view name or a
RedirectView.
After the redirect, attributes are automatically added to the model of
the controller that serves the target URL.
The errorMessage will be available in the model of getAllUsers() after the redirect .

ResponseEntity doesn't retrieve Integer

Want to return simple Integer in ResponseEntity:
#PreAuthorize("hasAnyAuthority('WORKER')")
#RequestMapping(value = "/countFiles", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Integer> countFiles(HttpServletRequest request){
Integer count = fileService.countFiles(request);
if(count == null){
return new ResponseEntity<Integer>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<Integer>(count, HttpStatus.OK);
}
When I do it, at front end site I got without filed named 'count':
Before you answer:
At front end site everything works fine
The bug is at backend site
If you want a field named "count", you need to include the field name in an object or map result.
#PreAuthorize("hasAnyAuthority('WORKER')")
#RequestMapping(value = "/countFiles", method = RequestMethod.GET)
public ResponseEntity<Integer> countFiles(HttpServletRequest request)
{
Integer count = fileService.countFiles(request);
if (count == null) {
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok(Collections.singletonMap("count", count));
}
FYI, it may be easier to use the static ResponseEntity.* methods to create new ResponseEntity instances. Also, you don't need #ResponseBody if the return value is ResponseEntity.

Render a view based on the conditional statement in Spring

I am kind of new to Spring. I am trying to render a view based on the the value returned from DBDAOImplementation class using a conditional if statement inside processController. I am trying to return successuseraddstatus jsp file for success scenarios and faileduseraddstatus jsp file for failed scenarios.
ProcessController.java:
#RequestMapping(value = "/adduserstatus", method = RequestMethod.POST)
public String addStudent(#ModelAttribute("SpringWeb")Process process,ModelMap model) {
model.addAttribute("fname", process.getFname());
model.addAttribute("lname", process.getLname());
model.addAttribute("email", process.getEmail());
model.addAttribute("phone", process.getPhone());
ApplicationContext context =
new ClassPathXmlApplicationContext("Beans.xml");
DBDAOImp dbd =
(DBDAOImp)context.getBean("JDBCTemplate");
dbd.createuser(process.getFname(), process.getLname(), process.getEmail(), process.getPhone());
if (true){ //This is where I am having trouble
return "successuseraddstatus";
}
return "faileduseraddstatus";
}
DBDAOImplementation.java:
#Override
public Boolean createuser(String fname, String lname, String email, String phone) {
isExists(email);
if (isExists==false){
String SQL = "insert into USERS (user_id,f_name,l_name,creation_date,email,phone) values (seq_users.nextval,?,?,sysdate,?,?)";
jdbcTemplateObject.update( SQL, fname,lname,email,phone);
System.out.println("Created Record");
return true;
} else {
return false;
}
}
Below if condition works. But I am not too sure if this is the right approach.
ProcessController.java:
#RequestMapping(value = "/adduserstatus", method = RequestMethod.POST)
public String addStudent(#ModelAttribute("SpringWeb")Process process,ModelMap model) {
model.addAttribute("fname", process.getFname());
model.addAttribute("lname", process.getLname());
model.addAttribute("email", process.getEmail());
model.addAttribute("phone", process.getPhone());
DBDAOImp dbd =
(DBDAOImp)context.getBean("JDBCTemplate");
if (dbd.createuser(process.getFname(), process.getLname(), process.getEmail(), process.getPhone())){
return "useraddstatus";
} else {
return "faileduseraddstatus";
}
}

how to return not found status from spring controller

I have following spring controller code and want to return not found status if user is not found in database, how to do it?
#Controller
public class UserController {
#RequestMapping(value = "/user?${id}", method = RequestMethod.GET)
public #ResponseBody User getUser(#PathVariable Long id) {
....
}
}
JDK8 approach:
#RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public ResponseEntity<User> getUser(#PathVariable Long id) {
return Optional
.ofNullable( userRepository.findOne(id) )
.map( user -> ResponseEntity.ok().body(user) ) //200 OK
.orElseGet( () -> ResponseEntity.notFound().build() ); //404 Not found
}
Change your handler method to have a return type of ResponseEntity. You can then return appropriately
#RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public ResponseEntity<User> getUser(#PathVariable Long id) {
User user = ...;
if (user != null) {
return new ResponseEntity<User>(user, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Spring will use the same HttpMessageConverter objects to convert the User object as it does with #ResponseBody, except now you have more control over the status code and headers you want to return in the response.
With the latest update you can just use
return ResponseEntity.of(Optional<user>);
The rest is handled by below code
/**
* A shortcut for creating a {#code ResponseEntity} with the given body
* and the {#linkplain HttpStatus#OK OK} status, or an empty body and a
* {#linkplain HttpStatus#NOT_FOUND NOT FOUND} status in case of a
* {#linkplain Optional#empty()} parameter.
* #return the created {#code ResponseEntity}
* #since 5.1
*/
public static <T> ResponseEntity<T> of(Optional<T> body) {
Assert.notNull(body, "Body must not be null");
return body.map(ResponseEntity::ok).orElse(notFound().build());
}
public static ResponseEntity of(Optional body)
A shortcut for creating a ResponseEntity with the given body and the OK status, or an empty body and a NOT FOUND status in case of an Optional.empty() parameter.
#GetMapping(value = "/user/{id}")
public ResponseEntity<User> getUser(#PathVariable final Long id) {
return ResponseEntity.of(userRepository.findOne(id)));
}
public Optional<User> findOne(final Long id) {
MapSqlParameterSource paramSource = new MapSqlParameterSource().addValue("id", id);
try {
return Optional.of(namedParameterJdbcTemplate.queryForObject(SELECT_USER_BY_ID, paramSource, new UserMapper()));
} catch (DataAccessException dae) {
return Optional.empty();
}
}
it could be shorter using Method Reference operator ::
#RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public ResponseEntity<User> getUser(#PathVariable Long id) {
return Optional.ofNullable(userRepository.findOne(id))
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
Need use ResponseEntity or #ResponseStatus, or with "extends RuntimeException"
#DeleteMapping(value = "")
public ResponseEntity<Employee> deleteEmployeeById(#RequestBody Employee employee) {
Employee tmp = employeeService.deleteEmployeeById(employee);
return new ResponseEntity<>(tmp, Objects.nonNull(tmp) ? HttpStatus.OK : HttpStatus.NOT_FOUND);
}
or
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="was Not Found")

Spring MVC 3, forwarding not working when using Ajax

I have very interesting problem. I am making log in page for my web app and I am sending login request via AJAX. If success I want to forward user to another page.
It seems that his is what happens. I send Ajax request, controller forwards me to need view (I see log in debug mode) but I stay on the same page, since I assume the page is waiting for AJAX response and for that reason forwarding does not happen.
I think this is also wrong way to approach this but since I am new to this don't know better. How can I log in and and forward user to next page.
Thank you.
Here is my code:
JS Code:
Page.authenticate = function() {
$.ajax({
url: "/login/authenticate/" + $('#username').val() + "/" + $('#password').val(),
type: "GET",
success: function(poi){
// alert("nesto");
}
});
return true;
}
Controller Class:
#Controller
public class LoginPageController {
private Logger logger = Logger.getLogger(this.getClass());
#Autowired
private UserManagement userManagement;
#RequestMapping(value="/login/authenticate/{username}/{password}", method=RequestMethod.GET)
public String authenticate(#PathVariable("username") String userName, #PathVariable("password") String password, Model model) {
if (userManagement.authenticateUser(userName, password)) {
String forward = "forward:/login/success";
return forward;
} else {
model.addAttribute("errorMessage", "Invalid Username/Password, please try again!");
return "/";
}
}
}
You need to response within #ResponseBody Annotation if you are using AJAX.
#RequestMapping(value="/login/authenticate/{username}/{password}", method=RequestMethod.GET)
public String authenticate(#PathVariable("username") String userName, #PathVariable("password") String password, Model model) {
if (userManagement.authenticateUser(userName, password)) {
String forward = "forward:/login/success";
return forward;
} else {
String forward = "forward:/login/error?message=Invalid Username/Password, please try again!";
return forward;
}
}
#RequestMapping(value="/login/success", method=RequestMethod.GET)
#Responsebody
public String handleMySuccessRedirect() {
return "Logged In successfully"
}
#RequestMapping(value="/login/error", method=RequestMethod.GET)
#Responsebody
public String handleMyExceptionOnRedirect(#RequestParamter("message") String message) {
return message;
}
Update:
#RequestMapping(value="/login/authenticate/{username}/{password}", method=RequestMethod.GET)
#ResponseBody
public String authenticate(#PathVariable("username") String userName, #PathVariable("password") String password, Model model) {
if (userManagement.authenticateUser(userName, password)) {
String response = "Logged Successfully";
return response;
} else {
String response = "Invalid Username/Password, please try again!";
return response;
}
}
There are a couple of things you can do here:
Don't return a view from your controller, instead return json, based on the response in json, set the location appropriately - window.location = 'home.action' - here is an example using ext-js
Let the login page perform a full fledged post, not an AJAX post.

Resources