Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Populating Db Tables With Dropdown Menu Using Spring/hibernate

hibernate spring database webapplication spring-mvc

  • Please log in to reply
15 replies to this topic

#1 dlinx90

dlinx90

    CC Regular

  • Member
  • PipPipPip
  • 34 posts

Posted 12 April 2012 - 01:38 PM

Hello everyone,

I was wondering how I would go about it if I wanted to make my web application so that I can populate my database using drop down menus which are filled by the existing objects from the relevant table?

I am creating a delivery management spring application using hibernate for ORM. Let's say for the sake of my question that I have two tables which look like this:

¦ Delivery_ID ¦ Product ¦ Customer_ID ¦ Date ¦
and
¦ Customer_ID ¦ CustomerName ¦ CustomerCountry¦

(The Customer_ID is unique to a CustomerName together with a CustomerCountry)

Since the users will for example not know the *Customer_ID* I want to be able to be able to have a page where the users are able enter a new delivery by filling in the Product, CustomerName, CustomerCountry and Date. My wish is for the first three to be drop down boxes where the user chooses from existing products, names and countries with the option to add a new one if it does not exist.

I have so far created the classes for the tables and mapped them using annotations.

My questions:

How do I deal with the fact that I want to add the new deliveries entering information into columns from different tables in the same view, excluding the Delivery_ID and Customer_ID? I would like for the application to automatically detect which Customer_ID the new delivery has by what Name and Country is entered (Given that combination already exists.)
Would I hard code this into my service layer or would it be something I would do in the Controller?

I realize this is a quite broad question so I don't expect any finished code for me to use (although I wouldn't say no to that ^^), just some tips on the architecture of my application.

Thank you for your time and help,

Best Regards,
D
  • 0

#2 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 12 April 2012 - 10:28 PM

I would create a form object, say class DeliveryRequest containing
Product, CustomerName, CustomerCountry and Date.

(look for spring databinding to get this object in the controller)
controller sends this object onward to the DeliveryService say method requestDelivery(DeliveryRequest request).
This method first uses CustomerService to retrieve the customer using name & country, then uses DeliveryDao to insert.
If customer has not been found you can throw an exception (see @ExceptionHandler in controller - no try catch required then)
Or your service can return something and then the controller must check the returnvalue to see if the request was good or not.

Finally, fill up the model to show the user the appropriate response.


Which version of Spring do you use?
  • 1

#3 dlinx90

dlinx90

    CC Regular

  • Member
  • PipPipPip
  • 34 posts

Posted 13 April 2012 - 12:00 AM

Thank you win DC for your reply. I will get right on looking up spring databinding. To answer your question I am currently using the spring-framework-3.1.0.RELEASE.

/D
  • 0

#4 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 13 April 2012 - 12:13 AM

Post number 4 gives a good, clean, example here:
http://www.coderanch...ring-form-input
  • 1

#5 dlinx90

dlinx90

    CC Regular

  • Member
  • PipPipPip
  • 34 posts

Posted 13 April 2012 - 04:50 AM

That example was really helpful to helping me understand better. I am a little bit confused on what the Service class and the DAO will contain and what their main functions are. For example this example doesn't use DAO: http://krams915.blog...any-to-one.html while this one does: http://labs.distrit....bernate-step-1/ . What is the difference?

Off topic: Also when should I use the @Autowire annotations that the second example uses?

Thanks,
D
  • 0

#6 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 16 April 2012 - 10:10 PM

Wall of text crit you for 9001 damage!
Sorry for the late reply , but here it finally is:


What I think the most common / basic design is:
Database <-> DAO <-> service <-> controller <-> JSP/JSF/FRONTEND

Usually there is 1 DAO per entity class (not necessarily 1 DAO / table)
It has the following methods: save, delete, update, selectById
Names vary: can be persist/store, remove/destroy, update
These methods don't HAVE to exist, make only those the application needs. If you never update the object, that method doesn't have to exist.

The DAO class also contains specific selects eg.: selectByName(String name) {...), selectAllManagers(), ....
Possibly specific update methods as well eg.: updateName(String name, Long PK), ...

It possibly autowires other DAOs to manage FK relations or fetch data from other tables(even though with JPA this is rather rarely required).

------

Services contain business logic (AND also manage transaction of the database (managed by spring annotation in most cases - You need a transactionmanager bean for that)).
Classic bank transfer example:
AccountService :
@Autowired private AccountDao accountDao;

@Transactional
public void transfer(Account from, Account to, int amount){
	if(amount > 0 && isWithdrawAllowed(from, amount)){
		accountDao.withdraw(from, amount);
		accountDao.deposit(to, amount);
	} else {
		throw new TransferFailedException(from, to, amount); //RunTimeException
	}
}

public boolean isWithdrawAllowed(Account account, int amount){
	return accountDao.getAccount(account.getId()).getAmount() > amount;
}
Throwing runtime exceptions is a more and more common thing to do to handle with 'special' situations.
Runtime exceptions end up with clean code as they don't require "throws ..." and "try-catch".
You may think it's unsafe to not require a try-catch, but chances are the service method is not called
by a controller but by another service, and it just KNOWS the amount will never be below 0 and the account is valid.

Besides, spring MVC has a rather clean way to deal with exceptions in controllers (@ExceptionHandler annotation)
Of course building the Exception objects is, compared to returning a true or false for example, an expensive thing to do.
So don't do missuse for common situation like "throw new TransferSuccessfulException()"

And lastly, you could of course check if the amount > 0 in the DAO, but that would be wrong.
DAO classes are rather "stupid" as they don't do a whole lot. They just put/get/update stuff from and to the database.
If the database, however, has restrictions on size. For example "name" is a varchar of size 25. The DAO would be the place to check for that.
If you want to check for that, you can also decide to not check it, and handle the thrown exception instead.
Difference is, if you check manually you can be sure that it's "name" which is wrong. If you handle the Exception you have to disassemble the exception to pull out of it what exactly went wrong if you like to give the user a concrete message

------------

Controllers handle incoming requests, build required objects and delegate onwards to the services after which they make responses.
Of course you can check for the amount > 0 in the controller as well. But I prefer to keep my controllers as stupid as possible.
I check if parameters are wrong though. And with wrong I mean like entering "13XXY4" as amount.
Additionally, if you decide to do the check in the controller, when the service method is called from another controller you'd have to do the check over there as well --> duplicate code.

Most likely, to stay with the bank account problem, the controller won't get full account objects as input. It'll rather receive 2 IDs from the request,
Controller will talk to AccountService to retrieve the 2 accounts, and then send it on to the transfer method.
Again, you can easily just send the IDs to the service's transfer method, and let the service deal with it and retrieve them from the DAOs.
But I prefer to have my services working with the model - with'real' objects, not with 'abstract' IDs

After the service call, the controller just prepares the "success" page (cause if something went wrong, an exception is thrown and the method would stop)

------------
------------

Thus far the classic design.
Now, Spring is a rather 'loose' framework by which I mean it doesn't require you to follow exactly this design / project setup.
Very often, your service class will look like this:

UserService class:
@Autowired UserDao userDao;

@Transactional
public void save(User user){
	userDao.save(user);
}

@Transactional
public void update(User user){
	userDao.update(user);
}

@Transactional
public void delete(User user){
	userDao.delete(user);
}

@Transactional
public void selectByUsername(String username){
	userDao.selectByUsername(username);
}

And that makes you think: What is the use of this service class, it does nothing.
And that is sad but true - it doesn't do anything at all but start a transaction. Having written many service classes like this makes people 'lose faith' in this design, and approach it differently.
Same with DAOs which are also pretty often one-liners when JPA is used (for basic insert/update/select/deletes)

The different approach usually consists of dropping (a part of) the service layer and/or the DAO layer. Which is what you've seen.

What I personally enjoy doing (but am not always allowed to :P) is put the DAO and simple service methods inside the model(@entity)
In essence it becomes:

@Entity
public class Account{
  @Id
  private Long id;
  ...
  //getter setter more fields

  public void save(){
entityManager.persist(this);
  }

  public void update(){
entityManager.merge(this);
  }

  public static Account selectById(Long id){
	entityManager.find(Account.class, id);
  }

  ...etc,

}

Why do I like this?
I think it's pretty to use the model afterwards.

accountDao.withdraw(from, amount);
accountDao.deposit(to, amount);

VS

from.withdraw(amount);
to.deposit(amount);

and also account.save(); account.update(), Account.findById(1), etc etc.
It just reads easier and feels better to use in my opinion.
You can write VERY readable code this way if you pick variables and method names well.
For example:
Account customer, shop;
int amount;
...
customer.transfersMoneyTo(shop, amount);
instead of accountService.transfer(customer, shop, amount)


Downside is you lose Spring's transaction management, as your model objects are not managed Spring beans.
So you'll need 'tricks' to get the entityManager into your model.
2nd downside: model classes may get big (but so nice to use afterwards :love: )




@Autowired ties the whole application together:
Database <-> DAO <-> service <-> controller <-> JSP/JSF/FRONTEND
Services have DAOs they use autowiredin them, controllers have the services they use autowired in them.
  • 1

#7 dlinx90

dlinx90

    CC Regular

  • Member
  • PipPipPip
  • 34 posts

Posted 17 April 2012 - 12:44 AM

Thank you wim DC for the most elaborate and pedagogic answer I have ever seen on a forum :) I have been doing a lot of googling on the subject but this was the best explanation I've seen and it finally made it clear to me. You are the best!

/D
  • 0

#8 dlinx90

dlinx90

    CC Regular

  • Member
  • PipPipPip
  • 34 posts

Posted 17 April 2012 - 05:02 AM

Post number 4 gives a good, clean, example here:
http://www.coderanch...ring-form-input


I have another question regarding the Form Object. In the controller code where it says "Fill in the form data somehow", how would I write it so that I fill it with what the application user enters from the GUI?
  • 0

#9 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 17 April 2012 - 05:14 AM

That initForm method is for when the users comes on the page the first time, not having entered anything yet.
For getting the data which the user has entered, you need to check the 'handleFormSubmit' method

If you want a form where the user enters 3 things, like:

<form:form action="/postForm" commandName="userFormObject" method="post">
<label>firstname: <form:input path="firstname"/></label>
<label>lastname: <form:input path="lastname"/></label>
<label>age: form:input path="age"/></label>
</form:form>



Then you'd have form class like:

public class UserForm{
private String firstname;
private String lastname;
private int age;

public UserForm(){ }

public String getFirstname(){
return firstname;
}

public void setFirstname(String firstname){
this.firstname = firstname;
}

public String getLastname(){
return lastname;
}

public void setLastname(String lastname){
this.lastname = lastname;
}

public int getAge(){
return age;
}

public void setAge(int age){
this.age = age;
}
}


Note the "path" attribute in the html must match the getters and setters without "set" and "get" and starting with a small letter.
If the user enters that data Spring will automagically create a UserForm object and fill all the data properly for your controller method.
Assuming it has the @modelAttribtue parameter


@RequestMapping(value = "/postForm", method = RequestMethod.POST)
public String handleFormSubmit(@ModelAttribute("userFormObject") UserForm userForm, Model model) {
//userForm should have all the data in it.
return "someResultView";
}


  • 0

#10 dlinx90

dlinx90

    CC Regular

  • Member
  • PipPipPip
  • 34 posts

Posted 17 April 2012 - 05:30 AM

Okay, so should I then leave the initForm like this:
@Controller 
public class MyController { 
  @RequestMapping(value = "/initForm", method = RequestMethod.GET) 
  public String formInitializationMethod(Model model) { 
    UserForm userForm = new UserForm(); 
	
    model.addAttribute("userFormObject", form); 
    return "somView"; 
  } 

Also, since I want to use the form data to persist it to the database in various tables, then would I call on some service to retrieve the data from the form object, or would I leave it to the controller?

Thanks
/D
  • 0

#11 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 17 April 2012 - 05:38 AM

Well, of course your variables must match :-P
@Controller
public class MyController {
  @RequestMapping(value = "/initForm", method = RequestMethod.GET)
  public String formInitializationMethod(Model model) {
	UserForm userForm = new UserForm();
                   v
                   +-------------------------v
	model.addAttribute("userFormObject", form);
	return "somView";
  }
And you can leave it like that IF you want to present the user an empty form.
Should the form already contain data (as it might be for updating an existing record in the database), then you'd have to fetch an object first, then set properties on the formobject.

As for persisting. Not quite sure why you want to retrieve data for persisting. But the standard way would be to let controllers talk with services. And the service does most of the work.
  • 0

#12 dlinx90

dlinx90

    CC Regular

  • Member
  • PipPipPip
  • 34 posts

Posted 17 April 2012 - 05:51 AM

Seems I was a little too eager to post my reply ^^

As for the retrieving data for persisting part I don't think I used the right word. What I'd like to do is use the data that the user fill in into the FormObject to make a service that retrieves the Id that corresponds with the form data (ex. retrieve CustomerID from CustomerName and CustomerCountry where the latter two were entered into the form object) and the persist that Id into the delivery table for the current delivery. Hope that makes sense.
  • 0





Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download