I used a couple of Java template engine (Mustache, Freemarker) and I always struggle on how to deal with the same problem.
Assume you have a template with a piece of code like:
<a href="/{{article.name}}/{{article.color}}/home.html">
where article is an object passed from a controller to the template engine, for instance.
Then, I always see the same problems. I have to hardcode the url in several pages, if I change it then I have to look at it manually everywhere. E.g., if I want to change the URI like this:
<a href="article/{{article.name}}/{{article.color}}">
Then I have to change it everywhere.
Yeah, maybe I can define each url in something that is enabled by specific template engines (e.g. includes), but I'm wondering if there is a best practice.
One possible solution I was thinking about is to create the urls on the server side (e.g. in the controller) and sending them to the view.
Which are the best approaches from the point of view of re-usability, correctness and flexibility?
You said it: The best (most flexible and maintenable) practice is to produce the URLs in the controller and send them to the view: That is called HATEOAS.
Related
We are currently using Thymeleaf to parse templates. We want to offer this feature to our users so that users can provide custom templates. However, Thymeleaf is very powerful and is able to call methods and access static resources.
Is there any way to disable both invoking Java methods (Or whitelist some vital calls), as well as disabling Thymeleaf from being able to access static fields and methods?
We only have to allow users to use basic IF statements, loops and accessing object fields.
In short - afraid not.
We are currently using Thymeleaf to parse templates. We want to offer this feature to our users so that users can provide custom templates. However, Thymeleaf is very powerful and is able to call methods and access static resources.
It is, and it's designed to do so with no (secure) way that I'm aware of for disabling this functionality. Even if you could disable what you want with some kind of preprocessor hack, relying on it being watertight seems incredibly risky to me - I really wouldn't advise it. (Even if users don't access anything untoward for instance, they could still execute random code repeatedly to bog the server down and make the page load slowly.)
Instead, I'd look to the more "normal" route of exposing the functionality that users are expected to see via an endpoint that they can call via AJAX. They can then build their forms in plain old HTML / JS, making additional calls to any other resources that they need along the way.
If you're worried about extra AJAX calls, you could also statically inject a JSON object that contains everything the user may need in the header of the page - they can then display the content of that wherever they want.
To get google tag manager data we need to add code provided by google into each and every page.
I dont want to manually add the code to each and every page component in CQ,as numerous templates can be created and it becomes manual job.
Instead i want to add the HTML code into my page on every page load.
Can i achieve this using service component(java class).
If not please, provide any alternative to achieve this.
Accounting for recent posts, your requirement, if I may paraphrase, says, "I want Google Tag Manager code included in all pages automatically, except on the pages where the author doesn't want it." In that case, your option is some form of component instance on every page, where the component's dialog.xml has a simple include GTM/don't include GTM checkbox. Alternatively, you could use a page property or a CQ5 tag. In any case, the author has to check the box or not.
you should use inheritance to achive this.
usually we got a so called "abstract" or "base" template which is more or less extending the foundtion page template were every other template can get kind of global code snipplets from.
You can put this "global" code into a seperate jsp within the abstract-template too and let people overwrite/disable that functionality in some of the extending templates (in case it is not needed in 100% of them) optionally too.
use this template in a way you would normally use the foundation components in every other template you are creating as resourceSuperType and there you go :-)
As suggested by chrysler you can use inheritance for this. Alternatively if you are very sure that you will need this google tag manager code in pretty much all the pages put the code in header/footer components assuming here that you are using header/footer in all the templates.
thanks for your reply. i am aware of this form of implementation wherein you create a parent page template and then refer to it via sling:resourceSuperType in all the child templates.
But what i wanted to know is if there is any other alternative wherein i dont have to host this code on the template's component, and the user can decide which page he wants to get tracked or not, who might not have coding knowledge.
I'm working on a servlet to perform some logic specific to a resourceType in sling and set information to the request to be accessible via the jsp then handing off the request to the jsp similarly to the first solution provided in this answer.
Here's some example code to represent my situation:
#SlingServlet(
resourceTypes="myapp/components/mycomponent",
methods="GET",
extensions={"html"}
)
...
#Reference
private ServletResolver serlvetResolver;
protected void doGet(....) {
setPropertiesToRequest();
Servlet servlet = servletResolver.resolveServlet(resource, "....jsp");
servlet.service(slingRequest, slingResponse);
clearPropertiesFromRequest();
}
Because of this, I've noticed that I've lost sling's selector handling (I've had to roll my own simpler version to determine which jsp to render. Full featured sling selector handling is described in more detail here). I wanted to reach out to the stack overflow community and ask what else I may be missing out on by depriving the default get handler of the request. I've scanned through the source code but I think there may be more going on.
Secondly, I'd be interested in thoughts on how and where this approach may impact performance of the request resolution.
Thanks, Thomas
Processing the business logic in Java and delegating to scripts for rendering sounds like a job for the recently released Sling Models. Using that should remove the need to implement your own handling of selectors, as those won't affect the model selection, only the rendering scripts.
Not sure what you are trying to achieve here, but the main problem seems to me that your SlingServlet handles the html extension and by itself does not have selectors to filter a bit more. Thus it of course intercepts all the requests to your component. Then you have to take care of the selectors again to be able to choose the correct JSP.
The question is, why do you use a SlingServlet for it when you anyway do the rendering by JSP?
Can't you implement your logic in the JSP or better in a bean referenced in the JSP?
In our company we use our custom tag that takes care of this, but there are public frameworks available from other Adobe Partner:
https://github.com/Cognifide/Slice
http://neba.io/index.html
I am working on a Spring Boot app using Thymeleaf & Spring MVC, and I came across a bug in the code where someone had bound the Spring MVC model to 2 different HTML form fields:
<input th:field="*{userModel.name}" type="text" />
<input id="name" th:field="*{userModel.name}" type="hidden" />
This was causing the name field in the model of the controller to get set to a string of comma-separated values. "Steve,Steve" for example. I fixed the problem, but I'm wondering the simplest way to write a regression test for this. There is a Spring MVC testing framework, which I could use as on this blog post, but what I really want to test is the interaction between the rendered template and the controller, not just the controller.
I could use a selenium test, but I recently read this Martin Fowler bliki/article (blikticle?) in which he says:
In particular a common problem is that teams conflate the concepts of end-to-end tests, UI tests, and customer facing tests. These are all orthogonal characteristics.
I think this is a great point. What I would like to write is a UI component (integration?) test, I think. Something smaller than loading up the whole page. Something only testing the form generation and submission.
Another idea I had was that this sort of bug might be best caught through a static-analysis tool, but that's a bit beyond my scope.
In this project, I've realized that the interactions between Spring MVC and the HTML forms are a common place for errors, so it would be nice to have a way to test just these interactions.
EDIT:
Upon further consideration, I think these are the steps I want in my test:
Select <form> tag out of a template's thymeleaf template and render it, passing in appropriate data on the model
Possibly programmatically edit the rendered form values (from Java) to simulate JavaScript interactions.
Generate a browser's http POST request based on rendered form.
Use whatever Spring uses to convert POST request to the controller's model parameter
Either call the controller and verify the results, or just assert that the model was created correctly
I think I may able to do #1 with Thymeleaf's fragment selectors or by refactoring my form out into a separate template. #2 I can do easily with JSoup. It's #3 & #4 that I'm not sure how to do. #3 I might be able to write myself maybe, depending on how the HttpServletRequest mocks work. #4 seems like it's gotta be available in Spring somewhere but I'm new to Spring.
UPDATE:
Looking at the WebDataBinder as a possible solution for #4.
A few years later, it looks like you can do now essentially what I wanted using HtmlUnit/SpringMVC Test integration. It will shortcut any calls you make to your controller and use MockMVC instead, without a Servlet Container.
So, you get the advantage of a html-smart client library to wrap the front end like a browser without the overhead of the servlet container and with the ability to mock out whatever you want to under the controller.
https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#spring-mvc-test-server-htmlunit
I think you should test the functionality and to get good path-coverage of the controller calling the controller directly, mocking the underlying services. Then you can test if the model is correctly filled.
You can test a complex template with Thymeleaf-test infrastructure.
However, at the end of the day, everything must work together. This test should be done with selenium, to check the the variable-names match (So your regression). Normally you should only need a few tests for each page. If you have a lot of JS you should test complex JS functionality with buster.js. The htmlunitdriver of selenium is really fast, so I assume that the performance shouldn't be a big issue. But don't test all controller- or service-paths with selenium.
First of all my language is not good and sorry for that and i am working with small organization and i am not getting coding standards or suggestions in the office .so let me know to which process uses in the well defined java projects among return List,Map and model object OR return ModelAndView from Controller in spring.Because for complex tables in the jsp's i think myself its not the better way to return json formatted List and handle them using jquery instead of that just throw a model and view and use static html components in the jsp's and populate the tables using model object.If you suggest return Collection List i need to add jackson processor jar files and having nearly 1mb size otherwise an jsp just 2kb size. Please help me to follow the correct way in what cases we generally use among one.Thanks in advance
Viswam,
The answer depends mostly on your application and the functionality you want to achieve, there is no standard solution here.
If your application is a single page application (read this wikipedia article) or you want RESTful application, I would suggest to stick with #ResponseBody, reason is simple, it supports AJAX and basically doesnt change the page from Server side.
You can easily populate any complex table using plain JavaScript or jQuery from the JSON response you receive.
Also if I were to think, I wouldn't want to waste my resources at server side for populating data in JSP and then send it over to client(browser) when it can do this by itself. But this is strictly a personal choice/preference.
And, If you need to redirect to or reload a page, I believe ModelAndView is the way to go.
Suggestion : You can check the Spring Code from various tutorials and projects on GitHub or similar platforms/blogs to learn how to keep your code clean and readable.
The best way to learn Best Practices is first code-reading and second actually Practicing them.
Also I dont think a dependency of 1 MB size should be a headache in today's world.