You can do that using command objects. They're validateable objects that can handle a list of domain instances. Example:
Command
import org.apache.commons.collections.ListUtils
import org.apache.commons.collections.Factory
@Validateable
class ItemsCommand {
List<Item> items = ListUtils.lazyList([], {new Item()} as Factory)
}
GSP
In your view you just need one form. When you create your fields, use the index like:
<g:each in="${command.items}" var="item" status="i">
<g:textField name="items[$i].url" value="${item.url}" />
...
</g:each>
Controller
//this is the submit action, the command will have the Item
//instances though Data Binding.
def myAction(ItemsCommand command) {
}