From request object to the database - spring

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 .

Related

How to send model attribute to spring controller

I want to test my controller using postman but don't know how to send a model attribute using postman. I even don't know whether it is possible or not.
My Controller seems like:
#Controller
#RequestMapping(path = "/api/v1")
public class PaymentController {
#Autowired
private CredentialsRepository credentialsRepository;
#PostMapping(path = "/charge")
public String charge(#ModelAttribute("pay-load") PayLoad payLoad, Model model) {
Credentials creds = credentialsRepository.findCredentialsById(1);
if (creds == null)
return "init_credentials";
return "charge";
}
}
Model Attribute
public class PayLoad {
private Integer mId;
private Integer ordId;
private Integer cardId;
private Integer cvvNo;
private String hash;
// getter & setter
}
I found the way to send model attributes to the spring controller.
see above screenshot for your reference.
Even you can pass all the key and value in requestParam from postman.
Instead of requestBody. ModelAttribute object treat each and every key and value as requestParam. It's just a way to combine a lot of requestParam in one object. Even you can try out with curl request, so it will make you more clear.
Thanks

Spring's RestTemplate: complex object to query params

I have a complex object like this:
public class ComplexObject {
private String a;
private String b;
...
private String z;
//getters and setters
}
I want to call a web service that receives all the complex object fields: http://localhost:8080/api/some_service?a=something&b=something&...&z=something
Is there any way to pass a ComplexObject to RestTemplate and have the work done automatically or I have to do the manual mapping by myself?
Thanks!
YES! there is a way to pass complete complex object to make the service call and then for sure it can be achieved automatically.
And for this you have to alter the way you send this complexObject and have to use HTTP POST (highly recommended ), as:
public HttpStatus send()
{
ComplexObject complexObj = getYourFilledObject();
ResponseEntity<HttpStatus> response = restTemplate.postForEntity(ROOT_URI, complexObj, HttpStatus.class);
return response;
}
And if not and GET is the only option then unfortunately you have to send as you’re. Because at the end of the day either you use rest templates ‘s function which intake params map or you create your own URI with params, it is the same HTTP GET and you have to achieve programmatically.
For examples & illustration you can visit here and best reference will be spring resttemplate doc

Java Spring REST, value from object (POST)

I have a quick question. I`m sending two params in a json object (user) from angular to my spring app using POST. When I display this object it is:
System.out.println(user.email);
{email=example#example.com, password=gfdgdfgf}
In Java my code is:
#RequestMapping(value="/userLogin", method = RequestMethod.POST)
public boolean userLogin(#RequestBody Object user, ModelMap model) {
...
}
But when I try to display the field from this object like:
user.password, it doesn`t work.
Many thanks for help!
You are mapping your data to an Object, which lacks the needed fields(email and password). You should create an entity class and use it instead. Jackson should be able to map your passed parameters.
public class User{
public String email;
public String password;
/* ... */
}

My spring mvc session was changed implicitly after called a service method?

I'm using spring 3.2.5 via annotations and got some issue dealing with session.
My controller class is like this:
#Controller
public class WebController {
#Autowired
private IElementService elementService;
...
//in this method I set the "elementList" in session explicitly
#RequestMapping("/elementSearch.do")
public String elementSearch(
#RequestParam("keyword") String keyword,
HttpSession session){
List<Element> elementList= elementService.searchElement(keyword);
session.setAttribute("elementList", elementList);
return "searchResult";
}
//here I got my problem
#RequestMapping(value="/anotherMethod.do", produces="text/html; charset=utf-8")
#ResponseBody
public String anotherMethod(
...
//I called my service method here like
Element e = elementService.searchElement("something").get(0);
...
}
And I have a ElementServiceImpl class like this:
#Service
public class ElementServiceImpl implements IElementService {
#Autowired
private IBaseDAO baseDao;
#Override
public List<Metadata> searchElement(String keyword) {
List<Metadata> re = baseDao.searchElement(keyword);
return re;
}
}
And I have a BaseDAOImpl class implemented IBaseDAO and annonated with #Repository:
#Repository
public class BaseDAOImpl implements IBaseDAO {
...
}
Here is the problem, when I visit ".../anotherMethod.do", which will call the anotherMethod up there, my "elementList" in session was changed!
Then I looked into the anotherMethod() and found everytime
Element e = elementService.searchElement("something").get(0);
was called, my elementList was change to the new result returned by searchElement method(which returns a List).
But I didn't set session in that method, and I'm not using #SessionAttributes, so I don't understand how could my session attribute changed after calling a service method?
This problem is torturing me right now so any advise would be a great help, thanks!
update: I tried to print all my session attributes around that method call like this:
StringBuilder ss1 = new StringBuilder("-------------current session-------------\n");
session.setAttribute("test1", "test value 1");
log.info("sessionTest - key:test1 value:" + session.getAttribute("test"));
Enumeration<String> attrs1 = session.getAttributeNames();
while(attrs1.hasMoreElements()){
String key = attrs1.nextElement();
ss1.append(key).append(":").append(session.getAttribute(key)).append("\n");
}
log.info(ss1);
But I didn't see whether the "elementList" or the test value which I added just before print. And I do can get some value by
List<Element> elementList = (List<Element>) session.getAttribute("elementList");
and the elementList I get changed after calling service method, just like I posted before. Where my elementList stored? not in the session?
My goal is to show the elementList to the users in a table, and let them pick one of them, then I get the row number of the table and take it as a index of the elemntList, so I'll know which elemnt object the user picked. Are there any better way to do this so I can get rid of that problem?
Thanks again.

Keep the state of an Object same in Spring MVC

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.

Resources