SpringBoot Page redirection error on controller - spring

I've tried a lot, but I can't find a reason, so I'm registering a question.
The following three examples are the output results according to the input.
'login_success' and 'login_failed' are both html pages in the template path.
The method 'loginSuccess()' or 'loginFailed()' was not executed in the failed debug result.
What's wrong with that? I need a hand..... ;(
Ex 1) (Successfully Run)
[input value] (Query values that are not in DB)
id = abc
password = 1234
[Expected output results]
redirect:login_failed
[Actual output results]
redirect:login_failed
Ex 2) (Failed Run)
[input value] (Query values that are not in DB)
id = abc#1234
password = abcd1234
[Expected output results]
redirect:login_failed
[Actual output results]
Redirection does not appear.
Ex 3) (Failed Run)
[input value] (Query values that exist in DB)
id = hihello1234#naver.com
password = byebye0000
[Expected output results]
redirect:login_success
[Actual output results]
Redirection does not appear.
And the following code is the logic of receiving View's customer information from the controller as DTo and querying it from the internal logic.
Controller
package My_Project.integration.controller;
import My_Project.integration.entity.Dto.LoginDto;
import My_Project.integration.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
#Controller
public class LoginController {
#Autowired
private
UserService userService;
#GetMapping("/trylogin")
public String login(LoginDto loginDto) {
try {
if (userService.login(loginDto)) {
return "redirect:/loginSuccess";
}
} catch (Exception e) {
return "redirect:/loginFailed";
}
return "redirect:/loginFailed";
}
#GetMapping("/loginSuccess")
public String loginSuccess() throws Exception {
return "login_success";
}
#GetMapping("/loginFailed")
public String loginFailed() throws Exception {
return "login_failed";
}
// 예외처리가 잘못된듯?....
}
Service
package My_Project.integration.service;
import My_Project.integration.entity.Dto.LoginDto;
import My_Project.integration.entity.Users;
import My_Project.integration.repository.UsersRepository;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
#Service
#RequiredArgsConstructor
#Getter
public class UserService {
#Autowired
private UsersRepository usersRepository;
public boolean login(LoginDto loginDto) throws Exception {
return usersRepository.checkUserInfo(loginDto.getId(), loginDto.getPassword());
}
}
Repository
package My_Project.integration.repository.UserCustom.Impl;
import My_Project.integration.entity.Users;
import My_Project.integration.repository.UserCustom.UserCustomRepository;
import lombok.RequiredArgsConstructor;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
import java.util.Optional;
#RequiredArgsConstructor
public class UserCustomRepositoryImpl implements UserCustomRepository {
private final EntityManager em;
#Override
public boolean checkUserInfo(String id,String password) throws Exception{
Optional<Users> matchedUser = Optional.ofNullable(em.createQuery("select u from Users u where u.id = :id", Users.class)
.setParameter("id", id)
.getSingleResult());
if (matchedUser.isPresent() || matchedUser.isEmpty()) {
if(matchedUser.get().getPassword().equals(password)) {
return true;
}else {
return false;
}
}
return false;
}
}

I see the issue in UserCustomRepositoryImpl Class, you are calling .get() even when matchedUser is empty which might be causing the problem. Separate both cases i.e. when the user is present and when it isn't and handle them accordingly.
When matchedUser is empty you can directly return a false. Also use the try-catch block here to check issue is here or not. In catch use Sysout to see the error.

Related

Mockito when().thenReturn doesn't give expected result

I am new to Junit and Mockito.
Trying to mock one of the object of the class, but it is not working.
The mock method is returning an empty list, due to which test case is getting failed.
This is the code which I have written.
Junit Test Class : Here I have mocked the object and method to return an Arraylist, but when the code is executed this mock method is returning an empty list due to which test case is getting failed.
package com.business;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.data.api.ToDoService;
public class TodoBusinessImplMockTest {
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void testRetrieveTodosRelatedToSpringUsingMock()
{
ToDoService todoServiceMock = mock(ToDoService.class);
List<String> todoList=Arrays.asList("Learn Spring MVC", "Learn Spring","Learn to Dance");
Mockito.when(todoServiceMock.retrieveTodos("Dummy")).thenReturn(todoList);
TodoBusinessImpl todoBusinessImpl = new TodoBusinessImpl(todoServiceMock);
List<String> todos = todoBusinessImpl.retrieveTodosRelatedToSpring("Ranga");
assertEquals(2, todos.size());
}
}
Interface : ToDoService.java
package com.data.api;
import java.util.List;
public interface ToDoService {
public List<String> retrieveTodos(String s);
}
TodoBusinessImpl.java
package com.business;
import java.util.ArrayList;
import java.util.List;
import com.data.api.ToDoService;
public class TodoBusinessImpl {
private ToDoService todoService;
TodoBusinessImpl(ToDoService todoService) {
this.todoService = todoService;
}
public List<String> retrieveTodosRelatedToSpring(String s) {
List<String> filteredTodos = new ArrayList<String>();
List<String> allTodos = todoService.retrieveTodos(s);
for (String todo : allTodos) {
if (todo.contains("Spring")) {
filteredTodos.add(todo);
}
}
return filteredTodos;
}
}
Your spec says:
Mockito.when(todoServiceMock.retrieveTodos("Dummy")).thenReturn(todoList);
but your call uses:
todoBusinessImpl.retrieveTodosRelatedToSpring("Ranga");
"Ranga" isn't "Dummy", therefore your spec isn't matched; therefore mockito returns the default result (which would be an empty list).
Try replacing the "Dummy" in Mockito.when(todoServiceMock.retrieveTodos("Dummy")).thenReturn(todoList); with anyString() (import static org.mockito.ArgumentMatchers.anyString;). This did the trick for me.

Detecting the insertion of data into the table and calling the method

I have an issue with detecting adding a new row to the table. I want to trigger a method from some service (Spring boot) when somebody executes an insert query on the database (Postgres)
Somebody told me I can use #Scheduled annotation and check if something was added using a repository. I have to make some changes instantly (by using another method). The scheduled method should run every 5 seconds to do this instantly. Of course, this is a really bad idea because it will kill the database someday and it's not efficient.
How can I do this better?
You can write concrete implementer of org.hibernate.integrator.spi.Integrator. and give it to hibernate.integrator_provider
From ServiceRegistry we can get EventListenerRegistry and then append listener of type EventType.POST_INSERT. More events here.
Main Reference Hibernate Integrator Ref
As per the query, I have also added how to call the service method from the listener class.
Here is how I have done it:
package com.example.samplejdbctemplatecall;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.boot.Metadata;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.jpa.boot.spi.IntegratorProvider;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
#RequestMapping(path = "/entity-listener")
#RestController
public class SampleLogController {
private final SampleLogRepository sampleLogRepository;
private final SampleLogEntries sampleLogEntiries;
#Autowired
public SampleLogController(SampleLogRepository sampleLogRepository, SampleLogEntries sampleLogEntiries) {
this.sampleLogRepository = sampleLogRepository;
this.sampleLogEntiries = sampleLogEntiries;
}
// This is usually post method but for test purpose creating new log with uuid random and inserting
#GetMapping(path = "insert")
public SampleLog insertNewEntry() {
final String uuid = UUID.randomUUID().toString();
final SampleLog sampleLog = new SampleLog();
sampleLog.setMessage(uuid);
return sampleLogRepository.save(sampleLog);
}
#GetMapping(path = "list-recent-inserts")
public Map<Long, String> entries() {
return sampleLogEntiries.data();
}
}
#Slf4j
#Component
class HibernateConfig implements HibernatePropertiesCustomizer {
private final JpaEventListenerIntegrator jpaEventListenerIntegrator;
#Autowired
HibernateConfig(JpaEventListenerIntegrator jpaEventListenerIntegrator) {
this.jpaEventListenerIntegrator = jpaEventListenerIntegrator;
}
#Override
public void customize(Map<String, Object> hibernateProperties) {
log.warn("Called hibernate configuration");
hibernateProperties.put("hibernate.integrator_provider",
(IntegratorProvider) () -> Collections.singletonList(jpaEventListenerIntegrator));
}
}
#Configuration
class SampleConfiguration {
#Bean
SampleLogEntries sampleEntries() {
return new SampleLogEntries();
}
}
class SampleLogEntries {
private final ConcurrentMap<Long, String> map = new ConcurrentHashMap<>();
public void add(SampleLog sampleLog) {
this.map.put(sampleLog.getId(), sampleLog.getMessage());
}
public Map<Long, String> data() {
return Collections.unmodifiableMap(this.map);
}
}
#Repository
interface SampleLogRepository extends CrudRepository<SampleLog, Long> {
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
class SampleLog {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String message;
}
#Service
#Slf4j
class JpaEventListenerIntegrator implements Integrator, PostInsertEventListener {
private final SampleLogEntries sampleLogEntiries;
#Autowired
JpaEventListenerIntegrator(SampleLogEntries sampleLogEntiries) {
this.sampleLogEntiries = sampleLogEntiries;
}
#Override
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
eventListenerRegistry
.appendListeners(EventType.POST_INSERT, this);
}
#Override
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
EventListenerGroup<PostInsertEventListener> eventListenerGroup = eventListenerRegistry
.getEventListenerGroup(EventType.POST_INSERT);
log.info("listener attached were: " + eventListenerGroup.getClass().getSimpleName());
log.error("disintegrate : " + getClass().getCanonicalName());
eventListenerGroup.clearListeners();
}
#Override
public void onPostInsert(PostInsertEvent event) {
log.info("Inserted : " + event.getEntity());
final Object entity = event.getEntity();
if (entity instanceof SampleLog) {
sampleLogEntiries.add((SampleLog) entity);
}
}
#Override
public boolean requiresPostCommitHanding(EntityPersister persister) {
return false;
}
}
The answer from #silentsudo is the best one if you only ever use JPA to update the table in question, and if you only have one process updating it.
The issue is that since you are being notified via the JPA interceptor, you won't be notified of any updates that happen outside of your JAP repository.
If you need these other notifications, then you can use Postgres' LISTEN/NOTIFY without polling by using an alternate postgresql JDBC driver, pgjdbc-ng, which implements async notifications.
With this method, you create a trigger in the database to send the notification, so you will be notified of other's updates as well. See https://www.openmakesoftware.com/postgresql-listen-notify-events-example

Is it a good idea to declare an injector and pass it as a state parameter when integrating typed Akka Actor with Spring

I could not find a neat way to integrate Spring with typed Actors.
Instead of using extensions I had declared an injector service
import akka.actor.typed.ActorSystem;
import com.akka.demo.a010.ASimpleSpringService;
import com.akka.demo.a010.AkkaSimpleBehaviour;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
#Data
public class ActorInjector {
#Autowired
private ASimpleSpringService aSimpleSpringService;
#Autowired
private ActorInjector _self;
public ActorSystem<AkkaSimpleBehaviour.Command> createAkkaSimpleBehaviour(String actorName) {
return ActorSystem.create(AkkaSimpleBehaviour.create(_self), actorName);
}
}
This service autowires itself and pass that reference to a simple actor.
My Actor definition is as follows.
import akka.actor.typed.ActorRef;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.ActorContext;
import akka.actor.typed.javadsl.Behaviors;
import akka.actor.typed.javadsl.Receive;
import com.akka.demo.a010.config.ActorInjector;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
#Slf4j
public class AkkaSimpleBehaviour extends AbstractBehavior<AkkaSimpleBehaviour.Command> {
private final List<String> messages = new ArrayList<>();
private ActorRef<List<String>> sender;
private ActorInjector actorInjector;
public interface Command extends Serializable {
}
#AllArgsConstructor
public static class TellMeSomething implements Command {
private static final long serialVersionUID = -7796709831949054890L;
#Getter
private final String message;
}
#AllArgsConstructor
public static class CollectTheResults implements Command {
private static final long serialVersionUID = 1643210899551075153L;
#Getter
private final ActorRef<List<String>> sender;
}
private AkkaSimpleBehaviour(ActorContext<Command> context, ActorInjector actorInjector) {
super(context);
this.actorInjector = actorInjector;
}
public static Behavior<Command> create(ActorInjector actorInjector) {
return Behaviors.setup(ctx -> new AkkaSimpleBehaviour(ctx,actorInjector));
}
#Override
public Receive<Command> createReceive() {
return newReceiveBuilder().onMessage(TellMeSomething.class, message -> {
messages.add(message.getMessage());
actorInjector.getASimpleSpringService().logSomething("*-*-*-*-*-*-*-*-*-*");
return Behaviors.same();
}).onMessage(CollectTheResults.class, message -> {
this.sender = message.getSender();
if (messages.size() == 4) {
this.sender.tell(messages);
}
return Behaviors.same();
}).build();
}
}
After passing the injector service I can get my autowired dependencies from that service like :
actorInjector.getASimpleSpringService().logSomething("*-*-*-*-*-*-*-*-*-*");
My ASimpleService is just a dummy service which logs an output.
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
#Service
#Slf4j
public class ASimpleSpringService {
public void logSomething(String message){
log.info(message);
}
}
Then in a simple RestController I am using the system as follows:
import akka.actor.typed.ActorSystem;
import akka.actor.typed.javadsl.AskPattern;
import com.akka.demo.a010.config.ActorInjector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
#RestController
#Slf4j
public class MyRestController {
#Autowired
private ActorInjector actorInjector;
#GetMapping("/hello-akka")
public void greetings() {
ActorSystem<AkkaSimpleBehaviour.Command> exampleActor = actorInjector.createAkkaSimpleBehaviour("anActor");
exampleActor.tell(new AkkaSimpleBehaviour.TellMeSomething("hello"));
exampleActor.tell(new AkkaSimpleBehaviour.TellMeSomething("Who are you"));
exampleActor.tell(new AkkaSimpleBehaviour.TellMeSomething("create a child"));
exampleActor.tell(new AkkaSimpleBehaviour.TellMeSomething("Here is some message"));
CompletionStage<List<String>> result = AskPattern.ask(exampleActor, AkkaSimpleBehaviour.CollectTheResults::new, Duration.ofSeconds(10), exampleActor.scheduler());
result.whenComplete((reply, failure) -> {
if(reply != null){
log.info("The system responds in time");
} else {
log.error("The system does not respond in time");
exampleActor.terminate();
throw new RuntimeException("The system does not respond in time");
}
exampleActor.terminate();
});
try{
List<String> messages = result.toCompletableFuture().get();
messages.forEach(log::info);
} catch (InterruptedException | ExecutionException e){
e.printStackTrace();
}
}
}
My question is : I am planning to put all of my services into my ActorInjector service and these services will be injected into my actors. I am not familiar with Akka states and its side-effects however I know that it may be a bad idea to store all of these singleton services as actor states. Is it a good idea to store these services as an actor parameter ? What kind of side effects can I experience by doing this way? Can you point me the way?

Spring - Failed to convert property value of type java.lang.String to required type

I am making a project of the Housing Association in Spring.
When I'm trying to add an object to my list of apartments I'm getting an error that is written somehow on the page:
https://s28.postimg.org/vrhy6mbd9/blad.jpg
Apartments have relation Many to One Building.
Apartment Controller:
package pl.dmcs.spoldzielnia.controllers;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import pl.dmcs.spoldzielnia.domain.Apartment;
import pl.dmcs.spoldzielnia.service.ApartmentService;
import pl.dmcs.spoldzielnia.service.BuildingService;
#Controller
#SessionAttributes
public class ApartmentController {
#Autowired
ApartmentService apartmentService;
#Autowired
BuildingService buildingService;
#RequestMapping("admin/apartment")
public String listApartment(Map<String, Object> map, HttpServletRequest request) {
int apartmentId = ServletRequestUtils.getIntParameter(request, "apartmentId" , -1);
if (apartmentId > 0)
{
Apartment apartment = apartmentService.getApartment(apartmentId);
apartment.setBuilding(buildingService.getBuilding(apartmentService.getApartment(apartmentId).getBuilding().getId()));
map.put("selectedBuilding", apartmentService.getApartment(apartmentId).getBuilding().getId());
map.put("apartment", apartment);
}
else
map.put("apartment", new Apartment());
map.put("buildingList", buildingService.listBuilding());
map.put("apartmentList", apartmentService.listApartment());
return "apartment";
}
#RequestMapping(value = "admin/addApartment", method = RequestMethod.POST)
public String addContact(#ModelAttribute("apartment") Apartment apartment, BindingResult result,
HttpServletRequest request, Map<String, Object> map) {
if (result.getErrorCount()==0)
{
if (apartment.getId()==0)
{
if (apartment.getBuilding().getId() > 0)
apartment.setBuilding(buildingService.getBuilding(apartment.getBuilding().getId()));
apartmentService.addApartment(apartment);
}
else
{
apartmentService.editApartment(apartment);
}
return "redirect:/admin/apartment.html";
}
map.put("buildingList", buildingService.listBuilding());
map.put("apartmentList", apartmentService.listApartment());
return "apartment";
}
#RequestMapping("admin/delete/apartment/{apartmentId}")
public String deleteApartment(#PathVariable("apartmentId") Integer apartmentId) {
apartmentService.removeApartment(apartmentId);
return "redirect:/admin/apartment.html";
}
// #RequestMapping("/apartment")
// public ModelAndView showContacts() {
//
// return new ModelAndView("apartment", "command", new Apartment());
// }
Domain:
package pl.dmcs.spoldzielnia.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="apartment")
public class Apartment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
int id;
#Column(name="apartmentNumber", nullable=false)
private String number;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#ManyToOne
private Building building;
public Building getBuilding() {
return building;
}
public void setBuilding(Building building) {
this.building = building;
}
}
}
Building Service Implementation:
package pl.dmcs.spoldzielnia.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pl.dmcs.spoldzielnia.dao.BuildingDAO;
import pl.dmcs.spoldzielnia.domain.Building;
import pl.dmcs.spoldzielnia.domain.Building;
#Service
#Transactional
public class BuildingServiceImpl implements BuildingService{
#Autowired
BuildingDAO buildingDAO;
#Transactional
public void addBuilding(Building building) {
buildingDAO.addBuilding(building);
}
#Transactional
public List<Building> listBuilding() {
return buildingDAO.listBuilding();
}
#Transactional
public Building getBuilding(int id) {
return buildingDAO.getBuilding(id);
}
#Transactional
public void removeBuilding(int id) {
buildingDAO.removeBuilding(id);
}
#Transactional
public void editBuilding(Building building) {
buildingDAO.editBuilding(building);
}
}
Could you help me to solve my problem?
The problem is that you are assuming that Spring MVC is going to be able to fill your Apartment object from the data passed. From the form it looks like the Building number is 12, which probably is a unique identifier for the Building in the database, but how is Spring MVC going to know how to go to the database, retrieve the proper building object and put it into the Apartment object?
Remember that objects mapped through SpringMVC parameters are regular Java POJOs, not Hibernate attached entities. So, when the mapping occurs SpringMVC is trying to put "12" into the building attribute of type Building into your POJO (which explains the error you are getting).
You have two options:
First, you can register a custom formatter, that will use the passed id to retrieve a Building from the database:
import org.springframework.core.convert.converter.Converter;
public class BuildingIdToBuildingConverter implements Converter<String, Building> {
private BuildingService buildingService;
public BuildingIdToBuildingConverter(BuildingService buildingService) {
this.buildingService = buildingService;
}
#Override
public Building convert (String id) {
return buildingService.getBuilding(id);
}
}
And register it:
public class AppConfig extends WebMvcConfigurerAdapter {
...
#Bean
public BuildingService buildingService(){
return new BuildingService();
}
#Override
public void addFormatters (FormatterRegistry registry) {
registry.addConverter(new BuildingIdToBuildingConverter(buildingService()));
}
}
Second, do this work manually by sending the building id in a separate parameter:
#RequestMapping(value = "admin/addApartment", method = RequestMethod.POST)
public String addContact(#ModelAttribute("apartment") Apartment apartment, #RequestParam("buildingId") String buildingId, BindingResult result, HttpServletRequest request, Map<String, Object> map) {
if (result.getErrorCount()==0){
if (apartment.getId()==0){
apartment.setBuilding(buildingService.getBuilding(buildingId));
apartmentService.addApartment(apartment);
}
}
else{
apartmentService.editApartment(apartment);
}
return "redirect:/admin/apartment.html";
}
map.put("buildingList", buildingService.listBuilding());
map.put("apartmentList", apartmentService.listApartment());
return "apartment";
}
And change your HTML accordingly to send the buildingId value.

Spring-Boot - Error Handling

I'm trying to write error handler in Spring-Boot for my controllers that would catch most possible errors (Spring, sql etc.). So far I'm able to get JSON response with Nulls however i'm unable to put any data inside. When I try to get error message in I just receive a blank page.
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
#RestController
public class BasicErrorController implements ErrorController {
private static final String ERROR_PATH = "/error";
#RequestMapping(value=ERROR_PATH)
#ExceptionHandler(value = {NoSuchRequestHandlingMethodException.class, SQLException.class, IOException.class, RuntimeException.class, Exception.class})
public ErrorBody defaultErrorHandler(HttpServletRequest request, Exception e) {
ErrorBody eBody = new ErrorBody();
eBody.setMessage(e.getCause().getMessage());
return eBody;
}
}
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
public class ErrorBody {
private String dateTime;
private String exception;
private String url;
private String message;
}
Yo can do something like this:
#ControllerAdvice
public class ControllerExceptionTranslator {
#ExceptionHandler(EntityNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
#ResponseBody
SimpleErrorMessage handleException(EntityNotFoundException exception){
log.debug("Entity Not Found Exception {}",exception.getMessage());
log.trace(exception.getMessage(),exception);
return new SimpleErrorMessage("Entity not found","This resource was not found");
}
#ExceptionHandler({UsernameNotFoundException.class})
#ResponseStatus(HttpStatus.UNAUTHORIZED)
#ResponseBody
SimpleErrorMessage handleException(UsernameNotFoundException exception){
log.debug("Username not found {}",exception.getLocalizedMessage());
log.trace(exception.getMessage(),exception);
return new SimpleErrorMessage("Unaouthorized"," ");
}
}
I was able to get to data about errors and send them as json properly by using "HttpServletRequest request" and reading information from request.
#RequestMapping(value = ERROR_PATH)
public ErrorBody defaultErrorHandler(HttpServletRequest request) {....}
Here this is an example of #ExceptionHandler(Exception.class)
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
You can use #ControllerAdvice
package demo.controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
#ControllerAdvice
public class ExceptionControllerAdvice {
#InitBinder
public void initBinder(WebDataBinder binder) {
System.out.println("controller advice: init binder");
}
#ExceptionHandler(Exception.class)
public String exception(Exception e) {
System.out.println("controller advice: exception Handler");
System.out.println(e.getMessage());
return "error";
}
#ModelAttribute
public void modelAttribute(){
System.out.println("controller advice:model Attribute");
}
}

Resources