i am using freemaker with spring boot.
every thing is working fine expect one.
when i am sending request and returning to user
it is showing that resource not found.
but when i am restarting my server
and refresh my browser it is working fine.
here is my rest controller method
#GetMapping("/activation")
public ModelAndView activateUser(#RequestParam(value="token") String token) {
LOGGER.info("inside #class UserController #method activation entry..");
Map<String, Object> model = new HashMap<String, Object>();
String msg = userService.activateUser(token);
if(msg != null) {
model.put("error", true);
model.put("message", msg);
}else {
model.put("error", false);
model.put("message", UtilMessages.USER_ACTIVATION_SUCCESS);
}
return new ModelAndView("user-activation-response",model);
}
also i am using #RestController but it is also behaving same with #Controller.
and my application property configuration as.
spring.freemarker.template-loader-path: classpath:/templates
spring.freemarker.suffix: .ftl
also when i am sending mail it is working fine with java mail.
Related
I am facing a problem regarding to the Httpsession that I implementing in the Spring MVC project.
First of all, after the user successfully login, I will take the Httpsession object in loginAuthentication controller and set attribute with the name and value I want. (Shown in following figure).
A.java controller file,
#RequestMapping(value="login-authentication", method = RequestMethod.POST)
public String authentication(#Valid #ModelAttribute("systemAccount") SystemAccount systemAccount,
BindingResult bindingResult, Model model, HttpServletRequest request){
if (bindingResult.hasErrors()) {
model.addAttribute(GenericConstant.MessageAttributeName.ERROR_MSG_NAME.toValue(), SystemMessage.SystemException.LOGIN_INCORRECT_USERNAME_PASSWORD.toValue());
model.addAttribute("systemAccount", new SystemAccount());
return "index";
}else {
if (systemAccountService.authenticate(systemAccount.getUsername(), systemAccount.getPassword()) != null &&
!"".equals(systemAccountService.authenticate(systemAccount.getUsername(), systemAccount.getPassword()))) {
SystemAccount dbSystemAccount = systemAccountService.authenticate(systemAccount.getUsername(), systemAccount.getPassword());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ID.toValue(),dbSystemAccount.getAccountID());
//check account role
if(dbSystemAccount.getCounterStaff()!= null && !"".equals(dbSystemAccount.getCounterStaff())){
CounterStaff counterStaff = dbSystemAccount.getCounterStaff();
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(), counterStaff.getStaffName());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(), GenericConstant.SystemRole.COUNTER_STAFF.toValue());
}else if(dbSystemAccount.getCustomer()!= null && !"".equals(dbSystemAccount.getCustomer())){
Customer customer = dbSystemAccount.getCustomer();
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(), customer.getCustomerName());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(), GenericConstant.SystemRole.CUSTOMER.toValue());
}else if(dbSystemAccount.getManager()!= null && !"".equals(dbSystemAccount.getManager())){
Manager manager = dbSystemAccount.getManager();
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(), manager.getManagerName());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(), GenericConstant.SystemRole.MANAGER.toValue());
}else if(dbSystemAccount.getDoctor()!= null && !"".equals(dbSystemAccount.getCounterStaff())){
Doctor doctor = dbSystemAccount.getDoctor();
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(), doctor.getDoctorName());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(), GenericConstant.SystemRole.DOCTOR.toValue());
}
request.setAttribute(SessionAttribute.AttributeName.LOGIN_DATE.toValue(), DateTimeUtil.getCurrentDate());
return "mainPage";
}else {
model.addAttribute(GenericConstant.MessageAttributeName.ERROR_MSG_NAME.toValue(), SystemMessage.SystemException.LOGIN_INCORRECT_USERNAME_PASSWORD);
model.addAttribute("systemAccount", new SystemAccount());
return "index";
}
}
}
After everything is ready, the controller will navigate user to the main page and the main page able to access all the defined variable without issue. (The following figure shown the controller that mapped with mainPage).
A.java controller file,
#RequestMapping(value = "/mainPage", method = RequestMethod.GET)
public String renderMainPageView(Model model, HttpServletRequest request) {
if(request.getAttribute(SessionAttribute.AttributeName.LOGIN_CHECK.toValue()) != null) {
model.addAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ID.toValue(),
request.getAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ID.toValue()));
model.addAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(),
request.getAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue()));
model.addAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(),
request.getAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue()));
model.addAttribute(SessionAttribute.AttributeName.LOGIN_DATE.toValue(),
request.getAttribute(SessionAttribute.AttributeName.LOGIN_DATE.toValue()));
return "mainPage";
}else {
model.addAttribute("systemAccount", new SystemAccount());
return "index";
}
}
In the navigation menu of main page, I click on the selection to direct me to add manager web page. (The following shown the link).
<a href="addManager" target="ifrm" >Add New Account</a>
The controller that mapped with the link (GET) able to detect. However, this controller (renderAddManagerView) does not recognised the HTTP session that I defined earlier when I try to access using the getAttribute method in the if condition. It keep showing null value (Shown in the following figure.
B.java controller file,
#RequestMapping(value = "/addManager", method = RequestMethod.GET)
public String renderAddManagerView(Model model, HttpSession httpSession) {
if(httpSession.getAttribute(SessionAttribute.AttributeName.LOGIN_CHECK.toValue()) != null) {
model.addAttribute("manager", new Manager());
model.addAttribute(FormSelectionValue.FormSelectionAttributeName.COUNTRY_SELECTION.toValue(), FormSelectionValue.COUNTRY_SELECTION_LIST);
model.addAttribute(FormSelectionValue.FormSelectionAttributeName.GENDER_SELECTION.toValue(), FormSelectionValue.GENDER_SELECTION_LIST);
return "addManager";
}else {
model.addAttribute("systemAccount", new SystemAccount());
return "index";
}
}
So I am not sure what is the issue for my code and there is no error message is displayed.
I have solved the issue by using the HttpServletRequest instead of HttpSession.
Now my session will not be loss even redirect or navigate to any pages in JSP.
Something like this:
#RequestMapping("/renderview", method = RequestMethod.GET)
#Controller
public class TestController {
#RequestMapping(method = RequestMethod.GET)
public String myMethod(HttpServletRequest request)
{
request.getSession().setAttribute("mySession", "XXX");
return "jspview";
}
}
Reference: Set session variable spring mvc 3
I am working with spring boot with a h2 database. I would like to return a 201 message when the register is inserted succesfully and a 400 when is duplicated. I am using ResponseEntity to achieve this, fot example , the next is my create method from the Service:
#Override
public ResponseEntity<Object> createEvent(EventDTO eventDTO) {
if (eventRepository.findOne(eventDTO.getId()) != null) {
//THis is a test, I am looking for the correct message
return new ResponseEntity(HttpStatus.IM_USED);
}
Actor actor = actorService.createActor(eventDTO.getActor());
Repo repo = repoService.createRepo(eventDTO.getRepo());
Event event = new Event(eventDTO.getId(), eventDTO.getType(), actor, repo, createdAt(eventDTO));
eventRepository.save(event);
return new ResponseEntity(HttpStatus.CREATED);
}
This is my controller:
#PostMapping(value = "/events")
public ResponseEntity addEvent(#RequestBody EventDTO body) {
return eventService.createEvent(body);
}
But I'm not getting any message in the browser, I am doing different tests with postman and when I consult for all the events, the result is correct, but each time that I make a post I dont get any message in the browser, I am not pretty sure what is the cause of this issue. Any ideas?
The ideal way to send Response to the client is to create DTO/DAO with ResponseEntity in Controller
Controller.java
#PostMapping("/test")
public ResponseEntity<Object> testApi(#RequestBody User user)
{
System.out.println("User: "+user.toString());
return assetService.testApi(user);
}
Service.java
public ResponseEntity testApi(User user) {
if(user.getId()==1)
return new ResponseEntity("Created",HttpStatus.CREATED);
else
return new ResponseEntity("Used",HttpStatus.IM_USED);
// for BAD_REQUEST(400) return new ResponseEntity("Bad Request",HttpStatus.BAD_REQUEST);
}
Tested using Postman
Status 201 Created
Status 226 IM Used
Okay, I really don't feel good that service sending the ResponseEntity but not Controller.You could use #ResponseStatus and ExceptionHandler classes for these cases, like below.
Create a class in exception package
GlobalExceptionHandler.java
#ControllerAdvice
public class GlobalExceptionHandler {
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(DataIntegrityViolationException.class) // NOTE : You could create a custom exception class to handle duplications
public void handleConflict() {
}
}
Controller.java
#PostMapping(value = "/events")
#ResponseStatus(HttpStatus.CREATED) // You don't have to return any object this will take care of the status
public void addEvent(#RequestBody EventDTO body) {
eventService.createEvent(body);
}
Now changing the service would look like,
Service.java
#Override
public void createEvent(EventDTO eventDTO) { // No need to return
if (eventRepository.findOne(eventDTO.getId()) != null) {
throw new DataIntegrityViolationException("Already exists"); // you have to throw the same exception which you have marked in Handler class
}
Actor actor = actorService.createActor(eventDTO.getActor());
Repo repo = repoService.createRepo(eventDTO.getRepo());
Event event = new Event(eventDTO.getId(), eventDTO.getType(), actor, repo, createdAt(eventDTO));
eventRepository.save(event);
}
While implementing a global exception handler in Spring, I noticed that in case of a not recognized Accept header, Spring would throw it's own internal error. What I need is to return a custom JSON error structure instead. Works fine for application specific exceptions and totally fails for Spring HttpMediaTypeNotAcceptableException.
This code tells me "Failed to invoke #ExceptionHandler method: public java.util.Map RestExceptionHandler.springMalformedAcceptHeaderException()" when I try to request a page with incorrect Accept header. Any other way to return custom JSON for spring internal exceptions?
#ControllerAdvice
public class RestExceptionHandler {
#ExceptionHandler(value = HttpMediaTypeNotAcceptableException.class)
#ResponseBody
public Map<String, String> springMalformedAcceptHeaderException() {
Map<String, String> test = new HashMap<String, String>();
test.put("test", "test");
return test;
}
}
Eventually figured that the only way is to do the json mapping manually.
#ExceptionHandler(value = HttpMediaTypeNotAcceptableException.class)
#ResponseBody
public String springMalformedAcceptHeaderException(HttpServletResponse response) {
// populate errorObj, set response headers, etc
ObjectWriter jsonWriter = new ObjectMapper().writer();
try {
return jsonWriter.writeValueAsString(errorObj);
} catch(Exception e){}
return "Whatever";
}
TL;DR - Is there a way to throw an error from a registered type converter during the MVC databinding phase such that it will return a response with a specific HTTP status code? I.e. if my converter can't find an object from the conversion source, can I return a 404?
I have a POJO:
public class Goofball {
private String id = "new";
// others
public String getName () { ... }
public void setName (String name) { ... }
}
and am using a StringToGoofballConverter to create an empty object when "new".equals(id) or try to load a Goofball from the database if it exists:
public Goofball convert(String idOrNew) {
Goofball result = null;
log.debug("Trying to convert " + idOrNew + " to Goofball");
if ("new".equalsIgnoreCase(idOrNew))
{
result = new Goofball ();
result.setId("new");
}
else
{
try
{
result = this.repository.findOne(idOrNew);
}
catch (Throwable ex)
{
log.error (ex);
}
if (result == null)
{
throw new GoofballNotFoundException(idOrNew);
}
}
return result;
}
That converter is used by spring when the request matches this endpoint:
#RequestMapping(value = "/admin/goofballs/{goofball}", method=RequestMethod.POST)
public String createOrEditGoofball (#ModelAttribute("goofball") #Valid Goofball object, BindingResult result, Model model) {
// ... handle the post and save the goofball if there were no binding errors, then return the template string name
}
This all works quite well insofar as GET requests to /admin/goofballs/new and /admin/goofballs/1234 work smoothly in the controller for both creating new objects and editing existing ones. The hitch is that if I issue a request with a bogus id, one that isn't new and also doesn't exist in the database I want to return a 404. Currently the Converter is throwing a custom exception:
#ResponseStatus(value= HttpStatus.NOT_FOUND, reason="Goofball Not Found") //404
public class GoofballNotFoundException extends RuntimeException {
private static final long serialVersionUID = 422445187706673678L;
public GoofballNotFoundException(String id){
super("GoofballNotFoundException with id=" + id);
}
}
but I started with a simple IllegalArgumentException as recommended in the Spring docs. In either case, the result is that Spring is returning a response with an HTTP status of 400.
This makes me think I'm misusing the Converter interface but that approach appears to be recommended by the #ModelAttribute docs.
So, again the question: is there a way to throw an error from a registered type converter during the databinding phase such that it will return a response with a specific HTTP status code?
Answering my own question:
Change StringToGoofballConverter to simply return null for the unfound entity instead of throwing IllegalArgumentException or a custom exception. The #Controller method will then be given a Goofball object that has a null id (e.g. the id is not "new" nor the path element value). At that point I can throw a GoofballNotFoundException or any other #ResponseStatus exception from there, within the controller method to affect the response status code.
I am new to Spring
I am having a page addContact,in that I am getting dropDown Data from Database in the following way
#RequestMapping("/addContact")
public ModelAndView registerContact(#ModelAttribute Contact contact) {
List<ContactType> contactTypeList = contactdao.getContactTypeList();
Map<Integer,String> contactTypeSelect = new LinkedHashMap<Integer,String>();
Iterator<ContactType> iterator = contactTypeList.iterator();
while (iterator.hasNext()) {
ContactType ct = iterator.next();
contactTypeSelect.put(ct.getContactTypeId(),ct.getContactTypeName());
}
Map<String, Object> map = new HashMap<String, Object>();
map.put("contactTypeSelect", contactTypeSelect);
return new ModelAndView("addContact", "map", map);
}
Now to Insert the Data into Database, I am having following method,
#RequestMapping("/insert")
public String insertData(#Valid Contact contact, BindingResult result, HttpServletRequest request ) {
if (result.hasErrors()) {
return "addContact";
}
else {
HttpSession session = request.getSession();
session.setAttribute("path", request.getSession().getServletContext().getRealPath("/WEB-INF"));
if (contact != null){
contactService.insertData(contact,request);
}
return "redirect:/getList";
}
}
When the validation fails, the drop down data is lost (which is obvious), what is the correct way of achieving the validation.
Create a method annotated with #ModelAttribute which loads the reference data. This method will be called before each #RequestMapping method.
#ModelAttribute("contactTypeSelect")
public List<ContactType> registerContact() {
return contactdao.getContactTypeList();
}
In your form you can use the <form:select ../> tag to render the itemValue and itemLabel.
<form:select items="${contactTypeSelect}" itemLabel="contactTypeName" itemValue="contactTypeId" />
With this you can refactor your addContact method to the following
#RequestMapping("/addContact")
public String registerContact(#ModelAttribute Contact contact) {
return "addContact";
}
You lose the drop down data because you're not adding in the contact map in the insertData method. Pull out the code where you grab the contact data into a separate (private) method and use it in the result.hasErrors() if block as such:
if (result.hasErrors()) {
return new ModelAndView("addContact", "map", map);
}
Also, I strongly suggest adding a method to the #RequestMapping annotation as such:
#RequestMapping("/insert", method=RequestMethod.POST)
This keeps people from making GET calls to this method.