I have a bunch of model classes in my Grails app, all of which are for the purpose of dynamic scaffolding of their respective database tables. For the index of the app, I'd like to have a menu of all these scaffoldings so that if a new model is added, the menu is updated.
Is there any automatic, Grails way of doing this or am I stuck with creating a naive index view with a bunch of g:link's statically typed out for each class to take the user to their respective CRUD views?
As an extension to Joshua's answer, the following should get you a list of scaffolded controllers, in grails 3 at least.
<g:each var="c" in="${grailsApplication.controllerClasses.findAll{ it.isReadableProperty('scaffold') } }">
<li><g:link controller="${c.logicalPropertyName}">${c.fullName}</g:link></li>
</g:each>
EDIT
As requested in the comments, to get the table name you'll need access to the sessionFactory which you'll need to inject into a controller, something like the following will get you a map of domain name to domain table name.
Controller
class YourController {
def sessionFactory
def index() {
def scaffoldedTables = grailsApplication.controllerClasses.findAll{ it.isReadableProperty( 'scaffold' ) }.collectEntries {
[(it.name): sessionFactory.getClassMetadata(it.getPropertyValue( 'scaffold', Object.class )).tableName]
}
[scaffoldedTables: scaffoldedTables]
}
}
gsp
<g:each var="c" in="${scaffoldedTables}">
<li><g:link controller="${c.key}">${c.value}</g:link></li>
</g:each>
You could just simply build a list of them like this:
<ul>
<g:each var="c" in="${grailsApplication.controllerClasses.sort { it.fullName } }">
<li><g:link controller="${c.logicalPropertyName}">${c.fullName}</g:link></li>
</g:each>
</ul>
This code was taken from an old Grails 1.3x project from the default index.gsp. Not sure if it still works in recent versions of Grails, but it should at least give you an idea of what you can do that would be dynamic.
UPDATE
As Jeff Scott Brown has pointed out this will include ALL controllers, scaffolded or not, and those provided by plugins as well. In theory you could further filter the resulting classes from grailsApplication.controllerClasses, inspecting them for their package (assuming your domain is in a known package or packages) and/or if they are scaffolded (static scaffold = true).
Related
I referred to Java MVC, and I understood the following.(please correct me if I'm wrong)
M->Model(It is a Java Bean)
V->View(JSP/HTML)
C->Controller(Servlet)
Here when going through Java Beans in JDBC there are getters and setters, I want to know if this is all the columns from my DB, for example, I've 10 Columns, Do I need to do a Getters and Setters for all the 10 Columns?
Should I write my JDBC code in Servlet or Bean?
In my JSP I've two textboxes that fetch data from Database Columns. for that I use to do something like below (Just for Demonstration sake).
`
<table>
<tr>
<td>
<input type="text" value="<%=i%>" name="id1" id="id1">
</td>
<td>
<center>
<input type="text" value="<%=rs.getString("DBID")%>" readonly="readonly" id="abc<%=i%>" name="abc<%=i%>" size="100">
</center>
</td>
<td>
<input type="text" value="<%=i%>" name="id2" id="id2">
</td>
<td>
<center>
<input type="text" value="<%=rs.getString("description")%>" readonly="readonly" id="ab<%=i%>" name="ab<%=i%>" size="100">
</center>
</td>
</tr>
</table>
`
Here I'm fetching content from database and putting it in 2 textboxes.
How can I do it using MVC approach?
1.Here when going through Java Beans in JDBC there are getters and setters, I want to know if this is all the columns from my DB, for example, I've 10 Columns, Do I need to do a Getters and Setters for all the 10 Columns?
Yes you need 10 properties with the getter and setter.
2.Should I write my JDBC code in Servlet or Bean?
The JDBC code should be in a service which is called from the controller or in the controller itself.
3.In my JSP I've two textboxes that fetch data from Database Columns. for that i use to do something like below(Just for Demonstration sake).
You have to call the getter of the bean for the property you need.
You can find good tutorials in the web.
Please do more study to understand for e.g. http://howtodoinjava.com/2015/02/05/spring-mvc-hello-world-example/
But i ll try to answer ur questions
1) Here when going through Java Beans in JDBC there are getters and setters, I want to know if this is all the columns from my DB, for example, I've 10 Columns, Do I need to do a Getters and Setters for all the 10 Columns?
-> A Java bean need not have "all" the columns, instead bean should reflect truly which fields (whether columns in DB tables or computed ones) are required at the "view" (or calling business logic).
2) Should I write my JDBC code in Servlet or Bean?
-> JDBC code can be put into a separate LAYER - read more about DAO and layered architectures. So a single controller class receives an event (request) and then call the appropriate "manager" class which know what bunisess action is requried. It can call other manager classes which intern can call DB layer (DAO will help here)
for e.g. suppose controller receives request to create Order -->
Controller.invoke(Request reqCreateOrder) --> CreateOrderHandler.execute(OrderBean ob) ---> OrderDao.create(OrderVO) ---> [insert query]
3) In my JSP I've two textboxes that fetch data from Database Columns. for that i use to do something like below(Just for Demonstration sake).
--> similarly for fetch as well
Controller.invoke(Request reqFetchOrder)
--> FetchOrderHandler.execute(OrderBean bean) ---> OrderDao.fetch(OrderBean bean) ---> [select query]
--> FetchOrderView.render(OrderVO bean) --> invokes JSP !!
MVC is just a paradygm. In real world you may have much more layers :
view (JSP) (the less possible scriptlet here)
front-controller (provided by a framework such as Spring MVC or Struts)
controller (provided by programmer) : processes request parameters, call next layer and forwards to a view
service : implementation of business rules <= here should be the intelligence
persistence (JDBC will come here, but you could have ORM such as Hibernate or JPA)
Object model (beans) go through all those layers.
It would be too long for a SO answer to explain all that so :
search on google and wikipedia for MVC and MVC2 patterns
read tutorials (Struts, Spring, Hibernate ...)
discuss with fellows that already used them => not to be done in SO
choose an architecture with or without framework (*)
try it and than ask precise question here if needed
(*) Even without framework try to separate view (JSP) - controller (servlet) - service - persistence
Short version
How is one supposed to make nested templates in Thymeleaf when using Spring? It appears asterisk notation is not supported ("*{mailingAddress}") inside th:object attributes in Spring. Is there a work-around / different tag to use?
Long version
For example, let's say I have these classes:
class Address { String street; }
class Person { Address mailingAddress; Address shippingAddress; }
class Order { int orderNo; Person customer; }
So I make an address.html Thymeleaf template:
<span th:text="*{street}"></span>
We test it with a sample Address. Looks good.
and I make a person.html Thymeleaf template that references the address like so:
<span th:text="*{firstName}"></span>
<span th:object="${person.shippingAddress}">
<span th:include="fragments/address :: address"></span>
</span>
And we test it with an example person. I could even reference the same template and set the context to be the ${person.mailingAddress}. So far so good.
Now let's make our Order template. Only, hey, wait. Earlier, in our person.html file we said ${person.shippingAddress} but now we need it to say ${order.customer.shippingAddress}. If I were not using Spring I'd put the following into person.html:
<span th:text="*{firstName}"></span>
<span th:object="*{shippingAddress}">
<span th:include="fragments/address :: address"></span>
</span>
That way, no matter what my path to getting here all I have to care about is that my current context has a shippingAddress. I could then use person.html directly as well as within my order.html template.
Unfortunately I am in Spring, so I get the following exception:
org.thymeleaf.exceptions.TemplateProcessingException:
The expression used for object selection is *{shippingAddress},
which is not valid: only variable expressions (${...}) are
allowed in 'th:object' attributes in Spring-enabled environments.
(include:510)
at org.thymeleaf.spring4.processor.attr.SpringObjectAttrProcessor.validateSelectionValue(SpringObjectAttrProcessor.java:73)
at org.thymeleaf.standard.processor.attr.AbstractStandardSelectionAttrProcessor.getNewSelectionTarget(AbstractStandardSelectionAttrProcessor.java:69)
at org.thymeleaf.processor.attr.AbstractSelectionTargetAttrProcessor.processAttribute(AbstractSelectionTargetAttrProcessor.java:61)
To move forward I must duplicate all my nested templates. In this example, I would have one person.html with th:object="${person.mailingAddress}" calling to address.html, and a duplicate of person.html called orderCustomer.html where we change the line to th:object="${order.customer.mailingAddress}", but is otherwise identical.
Is there a work-around out there that would let me re-use templates?
You can report a bug to the thymeleaf developers in github, or fork the project to add this functionality and convince the Daniel Fernández to accept it.
https://github.com/thymeleaf/thymeleaf/issues
Or else, he is available in StackOverflow. You can simply send him a message about the posibility of integrating this functionality
https://stackoverflow.com/users/550664/daniel-fern%C3%A1ndez
apart from that there is nothing much we can do rather to stick with the approach of putting th:object="${person.mailingAddress}" and th:object="${order.customer.mailingAddress}" outside each import.
I'm looking for a very simple form processing API for Java. Assuming the form input fields correspond to bean properties, and all beans have javax.Validation annotations, ideally the API would:
Display a bean as an html form
Populate the bean, including nested objects where applicable, using the request parameters
Validate the input using Validation annotation
If there is an error, display errors at top of form, and highlight error fields.
Additionally:
It would be nice if i didn't have to buy into a whole application framework, since I am working with a legacy app.
Allow configuration for more complicated use cases, but by default just use convention.
Bonus:
generates javascript client side validation too.
Note: If this requires several different libraries, that is fine too.
Update:
Since I never found what I was looking for, and migrating to Spring was not an option, I went ahead and rolled my own solution. It is, affectionately, called java in jails (loosely modeled on rails form processing). It gives you dead simple (and pretty) form creation, client and server side validation, and request parameter to object mapping. No configuration required.
Example Bean:
public class AccountForm {
#NotBlank(groups = RequiredChecks.class)
#Size(min = 2, max = 25)
private String name;
//...
}
Example Form:
<%# taglib uri="http://org.jails.org/form/taglib" prefix="s" %>
<s:form name="accountForm" action="/jails-demo/jails" label="Your Account Details" style="side">
<s:text name="name" label="Name" size="25" />
<s:text name="accountName" label="Account Name" size="15" />
...
</s:form>
Example Validation and Mapping:
SimpleValidator validator = new SimpleValidator();
if ("submit".equals(request.getParameter("submit"))) {
Map<String, List<String>> errors = validator.validate(AccountForm.class, request.getParameterMap());
if (errors != null) {
AccountForm account = validator.getMapper().toObject(AccountForm.class, request.getParameterMap());
//do something with valid account
} else {
SimpleForm.validateAs(AccountForm.class).inRequest(request).setErrors(errors);
//handle error
}
} else {
SimpleForm.validateAs(AccountForm.class).inRequest(request);
//forward to formPage
}
This is what the form looks like, with client side validation using jQuery (provided by Position Absolute):
I don't think you will find something that has most of this functionality and is not a framework.
I can recommend Spring MVC - you can plug it in easily in the legacy app. It supports all of the above.
Doing-it-yourself won't be that hard either:
use BeanUtils.populate(bean, request.getParameterMap()) to fill your object with the request parameters
use javax.validation.* manually - here is how. For each error add request attributes which you can later display as errors.
Note that either way you will have to write the html code manually.
I'm starting building web apps in Spring 3 (and in J2EE) in general.
Looking at the petclinic example I've seen that the programmer creates many JSP pieces, like header, includes, footer and then stitches them together using static inclusion. Anyway what I'd like is that I may have a base page, like Base.jsp and be able to include things like this:
<body>
<jsp:include page="${subpage}"></jsp:include>
</body>
the reason is that I'd like a main page, then being able to put in the ModelAndView returned by the controller which parts of the pages display in each situation (with the data attached to it). This works, but it gives no errors in case ${subpage} is not found, the jsp name is wrong or missing. I'd like more error checking...
Is this the best and recommended way to do this? And if this seems a good idea for what I've in mind, what's the correct way of doing it?
You might want to use Apache Tiles 2 integration for managing your JSP files. Spring has good integration support Apache Tiles. It also shows if there's an error in your page. I've put an example of it at http://krams915.blogspot.com/2010/12/spring-mvc-3-tiles-2-integration.html
It appears you have additional quotes in your subpage. Get rid of them. For example:
<c:set var="subpage" value="/jsp/index.jsp" />
If you have to set it in a controller or servlet - just use request.setAttribute("subpage", "/jsp/index.jsp")
For error checking you can use:
<c:catch var="myException">
<c:import url="${subpage}" />
</c:catch>
and later you can check it with:
<c:if test="${myException != null}">
...
</c:if>
Take a look at Sitemesh (http://www.opensymphony.com/sitemesh). It is a servlet filter-based page layout system that is easy to use. I have done a number of projects using it with Spring MVC and it worked very well.
is there a way to use groovy builders to build JSP files in a Grails application keeping things enough integrated?
To explain better: by default Grails uses gsp files that are nice but quite verbose..
<div class="clear">
<ul id="nav">
<li><g:link controller="snippets" action="list">Snippets</g:link></li>
<li><g:link controller="users" action="list">Users</g:link></li>
<li><g:link controller="problems" action="list">Problems</g:link></li>
<li><g:link controller="messages" action="list">Messages</g:link></li>
</div>
<div id="content">
is there a way to use groovy.xml.MarkupBuilder tha would turn the previous piece into
div(class:'clear') {
ul(id:'nav') {
li { g_link(controller:'snippets', action:'list', 'Snippets') }
// and so on
Of course g_link is invented just to give the idea..
Do a search for builder under the web layer section of the grails user guide. There is an example in there that shows you exactly how to do this using the xml builder.
I don't have a complete answer for you, but I suspect the key will be gaining access to the "view resolvers". In a normal SpringMVC app, these are configured in views.properties (or views.xml) as follows:
csv=com.example.MyCSVResolver
xml=com.example.MyXMLResolver
audio=com.example.MySpeechResolver
In a regular SpringMVC app, you return something like new ModelAndView(myModel, 'csv') from a controller action.
This would cause the CSVResolver class to be invoked passing it the data in myModel. In addition to containing the data to be rendered, myModel would likely also contain some formatting options (e.g. column widths).
Spring searches the views file for a key matching the view name. If it doesn't find a match, by default it just renders a JSP with the view name and passes it the model data.
Now back to Grails....remember that Grails is really just a Groovy API over SpringMVC and most of the features of SpringMVC can be accessed from Grails. So if you can figure out how to modify the views file, just change your controller actions to return an appropriate ModelAndView instance, and it should work as described above.
GSP allows you to run arbitrary Groovy code inside <% %> brackets. So you can have something like this (borrowing example from page linked to by BlackTiger):
<% StringWriter w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.html{
head{
title 'Log in'
}
body{
h1 'Hello'
builder.form{ }
}
}
out << w.toString()
%>
Note that the above calls g:form tag, and you can pass additional stuff to it.
So what you are asking for is certainly possible, though I am not sure if it will end up being a win. I'd suggest you perhaps look more at TagLibs in combination with Templates and SiteMesh Layouts - can definitely simplify things tremendously.