In our application we are having a requirement that we need to make the entry in database of an object and then send it to the user to make the changes in the same. As shown in the below -:
#RequestMapping(value = "/addCompany", method = RequestMethod.POST)
public ModelAndView addCompany(
#ModelAttribute("company-entity") Company company,
BindingResult result) {
CompanyService companyService = (CompanyService) applicationContext
.getBean("companyService");
companyService.saveVersionAsDraft(company, 1110);*/
return new ModelAndView("success");
}
//Delegate to addPage after making an entry in the database
#RequestMapping("/companyHome")
public ModelAndView showCompanyForm() {
System.out.println("CompanyController.showContacts()");
CompanyService companyService = (CompanyService) applicationContext
.getBean("companyService");
CommonService commonService = (CommonService) applicationContext.getBean("commonService");
Company company = (Company) companyService.addNew(new Company(), 1100);
ModelAndView modelAndView = new ModelAndView("company");
modelAndView.addObject("companyCategories",
companyService
.findAllCompanyCategories());
modelAndView.addObject("sectors", commonService.findAllSectors());
modelAndView.addObject("companyStatus",
companyService.findAllCompanyStatuses());
ModelAndView modelAndView = new ModelAndView("company");
modelAndView.addObject("company-entity",company);
return modelAndView;
}
Now in this company object we are also passing primary Key of Db which we need to use in add Company() . So we need to return this primary Key with the object from the form.
Is there any way to do so ?
We are having 6 to 7 entries of this kind so we cant use hidden field in the form.
Like JB Nizet said, it seems you absolutely not make use of the core of Spring : the Dependency Injection.
Instead of using a direct get of a service bean :
CompanyService companyService = (CompanyService) applicationContext
.getBean("companyService");
You should let Spring inject it with someting like that in your controller :
#Autowired
private CompanyService companyService;
Besides that, about your question, you have three options to keep the id. The first solution use the classic way proposed by Spring to edit some domain object (inspired by the RestFull approach) :
//Delegate to addPage after making an entry in the database
#RequestMapping("/company/{id}")
public ModelAndView showCompany(#PathVariable("id") Long id,Model model) {
Using this you will always have the id in the url, so you will keep it.
The second option is available if you take advantage of 'form' tags of Spring. You will just need to create a form:hidden field and give him the path="yourIdAttribute"
The third is similar but you have to create a standard input type="hidden" and then get it in your controller with someting like that :
public ModelAndView showCompany(#RequestParam(value="name_of_your_field") Long id,...)
Don't hesitate to ask if you need more details.
Related
In a Servlet, you can include an #Override service method which gets called before the doGet or doPost, is there a way to achieve the same in a Spring #Controller?
Or more precisely, in each method in the Controller, I need to make sure an Entity (in this case, a Product) exists and redirect otherwise, like so, so how would one achieve that in Spring? Note that I also need the Product available in each Method.
#Controller
#RequestMapping("/product/{prod_id}/attribute")
public class AttributeController {
#Autowired
private AttributeService attributeService;
#RequestMapping(value = "/add", method = RequestMethod.GET)
public String add(Model model, #PathVariable Long prod_id) {
Product product = attributeService.getProduct(prod_id);
if (product == null) {
return "products/products";
}
model.addAttribute("product", product);
model.addAttribute("attribute", new Attribute());
return "products/attribute_add";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String save(Model model, #PathVariable Long prod_id, #Valid Attribute attribute, BindingResult result) {
Product product = attributeService.getProduct(prod_id);
if (product == null) {
return "products/products";
}
// ...
}
// ...
}
This can be done with HandlerInterceptor. All you need to do is to extend HandlerInterceptorAdapter#preHandle and then register your interceptor through WebMvcConfigurer#addInterceptors. You can choose to use interceptor with all your mappings or with some specific mappers through InterceptorRegistration object with is returned by InterceptorRegistry#addInterceptor method.
By the way, HandlerInterceptors are useful to do some utility operations with requests and responses in general, like logging, adding headers, authentication, etc. For business-related operations I would recommend to use ControllerAdvice with custom business-oriented exceptions. In this case it would be a method which retrieves Product from database and throws custom exception if not found.
I have a Roo generated application and use validation, spring security with a custom PermissionEvaluator and the generated web controllers. My entity has a field like this:
#NotNull
private Date creationDate;
This field is set automatically inside the controller's create method when saving the entity and is not included in the form (render="false").
#RequestMapping(method = RequestMethod.POST, produces = "text/html")
#PreAuthorize("hasPermission(#myEntity, 'create')")
public String create(#Valid MyEntity myEntity,
BindingResult bindingResult, Model uiModel,
HttpServletRequest httpServletRequest) {
// ... check binding result
myEntity.setCreationDate(new Date());
myEntity.persist();
// ...
}
The problem is, that validation always fails because it runs before the field is set. The PermissionEvaluator (called by #PreAuthorize) is also missing the value. How can I place my code somewhere between data binding and validation so that the entity is complete right from the beginning?
To solve the problem of #PreAutorize move the persistence logic to a #Service bean and call it from the controller. This way security check will be after validation. Roo can help you on it with service command.
Second, you can use validation groups to make different validation on for the same entity. This and this are two howto post.
An example:
#RequestMapping("/myEntity")
public MyEntityController {
#Autowired
MyEntityService myEntityService;
#RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String create(#Validated({Account.ValidationStepOne.class}) MyEntity myEntity,
BindingResult bindingResult, Model uiModel,
HttpServletRequest httpServletRequest) {
// ... check binding result
myEntityService.save(myEntity);
//...
}
}
#Service
public MyEntityService {
#PreAuthorize("hasPermission(#myEntity, 'create')")
public save(MyEntity myEntity) {
//...
myEntity.setCreationDate(new Date());
myEntity.persist();
}
}
Good luck!
I have an app with an AngularJS front-end and a Spring MVC back-end. I'm having some trouble with converting/mapping request objects to domain/dto objects.
On one page you can add a new order to the system, the POST payload would look something like this:
{
memo: "This is some extra info for order",
orderLines: [{productId:3, quantity:4}, {productId:2, quantity:5}, {productId:1, quantity:4}],
shippingDate: "2014-10-08T19:16:19.947Z",
warehouseId: 2
}
The Spring MVC controller method looks like this:
#RequestMapping(value = "/order", method = RequestMethod.POST)
public ResponseEntity<Void> addOrder(#RequestBody #Valid OrderRequest orderRequest, UriComponentsBuilder b) throws Exception {
// the magic
}
Where OrderRequest is filled with the values of the POST request, the OrderRequest and OrderLineRequest look like this:
public class OrderRequest {
private Long id;
private Date shippingDate;
private String memo;
private List<OrderLineRequest> orderLines;
private Long warehouseId;
public OrderRequest() {
}
// getters and setters ommitted
}
public class OrderLineRequest {
private Long id;
private String productCode;
private int quantity;
public OrderLineRequest() {
}
}
My question now is, in order to save an Order object with orderService.add(order) I need to construct the Order object based on the values that were sent in the request. Where/how do I do this?
OPTION 1
The OrderRequest class could have a makeOrder() method with just returns an Order object like so:
public Order makeOrder() {
Order order = new Order();
order.setMemo(this.memo);
order.setShippingDate(this.shippingDate);
...
}
Then I'd have to map the OrderLineRequest which could have their own makeOrderLine method:
public OrderLine makeOrderLine() {
OrderLine orderLine = new OrderLine();
orderLine.setQuantity = this.quantity;
...what to do with only the productId?
}
As you can see I can set the quantity but in the request I only received the productId, but in the database I save the productCode, productName as well, so I need that info from the database, but I don't want to make a database call from the Request object...I also don't want to half of the mapping in the request object and the rest of the mapping in the controller where I do have access to the services.
OPTION 2
I can use Dozer to do the mapping for me, but that would mean injecting the services into the Dozer custom converters which seem equally unclean to me...
OPTION 3
I pass the OrderRequest object to the service layer and let the service layer handle it, but my question would remain, how exactly would the service layer convert it, say you have the method addOrder like this:
public void addOrder(OrderRequest orderRequest) {
}
Would you call another service to convert from one to the other as I don't really want this conversion in a business logic method?
Any help would be appreciated
use the #RequestBody to map your jsonObject that is send with the request , to a DTO .
please refer to the following tutorial .
hope that helps .
and please ask if there is something not clear .
I have developed a Spring MVC - Hibernate application as told here.
Now I am trying to modify this code to create a REST application as told here.
I have added Jackson library to the classpath and added #XmlRootElement.
#XmlRootElement(name = "persons")
public class Person implements Serializable {
But if I do a application/json request then I still get the html code back.
What I am doing wrong / forgot to do?
My controller:
#RequestMapping(value = "/persons", method = RequestMethod.GET)
#ResponseBody
public String getPersons(Model model) {
logger.info("Received request to show all persons");
// Retrieve all persons by delegating the call to PersonService
List<Person> persons = personService.getAll();
model.addAttribute("persons", persons);
return "personspage";
}
Changed the Controller, but get an error:
t
ype Status report
message /Buddies/WEB-INF/jsp/main/persons/1.jsp
description The requested resource (/Buddies/WEB-INF/jsp/main/persons/1.jsp) is not available.
Your controller should look like this:
#RequestMapping(value = "/persons/{id}", method = RequestMethod.GET)
#ResponseBody
public Person getPerson(#PathVariable int id) {
Person person = personService.getPersonById(id);
return person;
}
If you want to return a list of Person objects, you need an extra wrapper object, see: Using JAXB to unmarshal/marshal a List<String>.
You are probably missing AnnotationMethodHandlerAdapter and messageConverter in your spring configuration.
I am using session.setAttribute to store user object after login. In next controller, I have #SessionAttribute for the same user and #ModelAttribute for same object to be used in the method mapped to a RequestMapping. After login if I click any link in the user home page it give
HttpSessionRequiredException: Session attribute '' required - not found in session
I am not sure what I am doing wrong. I went through many article and question in this site as well but could find any solution. The user object which I am storing in session stores user's account details which are required in all the controller to get different information from DB. I using SessionAttribute is wrong should I use HttpSession instead in all the controller and get the object from session manually or there is a proper way to handle in spring 3.0. Please note that this user object is not backing any form just login, but contains many other details.
As help would be good.
Have a look at my (non-perfect) use of session data:
#Controller
#SessionAttributes("sharedData")
public class RegistrationFormController {
#Autowired
private SharedData sharedData; // bean with scope="session"
#RequestMapping(value = {"/registrationForm"}, method = RequestMethod.GET)
public ModelAndView newForm() {
final ModelAndView modelAndView = new ModelAndView("registrationForm");
modelAndView.addObject("registrationForm", new RegistrationForm());
// I want to render some data from this object in JSP:
modelAndView.addObject("sharedData", sharedData);
return modelAndView;
}
#RequestMapping(value = {"/registrationForm"}, method = RequestMethod.POST)
public String onRegistrationFormSubmitted(HttpServletRequest request,
#ModelAttribute("registrationForm") RegistrationForm registrationForm, BindingResult result) {
if (result.hasErrors()) {
return "registrationForm";
}
// Perform business logic, e.g. persist registration data
return "formSubmitted";
}
}