Sling:alias vs vanityUrl in AEM - aem

what is the main difference between vanity url and sling:alias?
as per docs : here
sling:alias – The property may be set on any resource to indicate an alias name for the resource. For example the resource /content/visitors may have the sling:alias property set to besucher allowing the resource to be addressed in an URL as /content/besucher.
Vanity URL - You define Vanity URLs in CQ to create easy-to-remember and easy-to-search URLs on your website.
But still I can not sure what exactly is the difference and when do we use them.
Please help me out in this.

I think that the main difference is that with sling:alias you may set just other name where the resource is available (note name, but not path) and with sling:vanityPath you define absolute virtual path to access this resource. So for example if you have the following structure:
content
└── visitors(sling:alias=besucher, sling:vanityPath=/besucher)
└── area(sling:alias=bereich)
├── a(sling:vanityPath=/bereich/a)
└── b(sling:alias=c,sling:vanityPath=/bereich/b)
You can access the above pages also in the following ways:
/content/besucher.html -> /content/visitors
/content/besucher/area.html -> /content/visitors/area
/content/besucher/bereich.html -> /content/visitors/area
/content/besucher/area/a.html -> /content/visitors/area/a
/content/besucher/area/b.html -> /content/visitors/area/b
/content/besucher/bereich/a.html -> /content/visitors/area/a
/content/besucher/bereich/b.html -> /content/visitors/area/b
/content/besucher/bereich/c.html -> /content/visitors/area/b
/besucher -> /content/visitors
/bereich/a -> /content/visitors/area/a
/bereich/b -> /content/visitors/area/b

Related

How to use DiscoveredResource to traverse to a single entity resource exposed by a RepositoryRestResource

I'm trying to set up a system with multiple applications connecting by use of a discovery server. I can traverse the hal responses to a specific resource, but I'm looking for a solution to get from a collection resource to a single resource and find the data for a specific entity.
In 1 application I have a RepositoryRestResource exposing some object:
#RestRepositoryResource(collectionResourceRel="things", itemResourceRel="thing") public interface ThingRepo extends CrudRepository<Thing,Long> {}
In some other application, I would like to get to a single thing. I have the id (let's say it's 1) and have the relation name of the collection and the single resource.
I would like to use a DiscoveredResource to get a link to this single item resource, or to the collection resource which I can then somehow expand using the ID (which would require a templated resource).
If at all possible I would not like to just add "/1" at the end of the URL.
this is how I currently create a DiscoveredResource to point to the collection resource:
new DiscoveredResource(new DynamicServiceInstanceProvider(discoveryClient, traverson -> traverson.follow("things"));
Should I and is it possible to add a templated link on a collection resource created by a #RepositoryRestResource. Or is there some other trick I am missing?
The solution here is to add a custom method as a #RestResource which exposes a relation with a templates URL you can then follow to.
Repo:
#RestRepositoryResource(collectionResourceRel="things", itemResourceRel="thing") public interface ThingRepo extends CrudRepository<Thing,Long> {
#RestResource(rel = "thing")
Thing findOneById(#Param("id") Long id);
}
Discovery + traverson:
DiscoveredResource resource = new DiscoveredResource(new DynamicServiceInstanceProvider(discoveryClient, traverson -> traverson.follow("things","search","thing"));
Link link = resource.getLink().expand(id);

AEM Internal Redirect

I'm trying to do an internal redirect in AEM 6.3, what I'm trying to do is: any request coming to localhost:4502/aem should be redirected to localhost:4502/content/myapp/en/login.html. So I created a sling:mapping node under /etc/map/http/:
jcr:primaryType="sling:Mapping"
sling:internalRedirect=/content/myapp/en/login.html -> Type String
sling:match=localhost.4502/aem -> Type String
I'm getting an Internal Server Error: Cannot serve request to /aem on this server. But if I add the .html suffix (request to localhost:4502/aem.html it works and redirects correctly.
Also tried:
sling:match=localhost.4502/aem(.*)(/.*)?
I wonder what I'm missing/doing wrong. Thanks in advance for your help.
I solve it using sling:redirect instead of sling:internalRedirect, not sure if this is the proper solution, but is working:
jcr:primaryType="sling:Mapping"
sling:redirect=localhost:4502/content/myapp/en/login.html -> Type String
sling:match=localhost.4502/aem -> Type String
If you have a better option, feel free posting it, Thanks.
I would recommend you go to http://localhost:4502/system/console/jcrresolver to check whether your redirects are correct or incorrect!
for example your
CRXDE Internal URL is http://localhost:4502/content/app1/en-in/home.html
and preferred external URL is http://localhost:4502/home/
There are to options you will be able to see
map:
map returns you the external URL when you enter internal URL. Remember to add .html at the end.
resolve:
resolve does the reverse of map. Remember to add .html at the end while testing.

AEM Custom component for page redirect

I am trying to create a custom component for page redirect. The use case is pageB should be accessible only via pageA. If pageB is accessed directly then user should be redirected to pageA.
In order to achieve this, I am setting a variable in pageA's request scope. In pageB i will be including a component(drag and droppable), which will look for pageA's request scope variable and if it is not available then we pageB will be redirected, using below snippet.
private void redirect(SlingHttpServletRequest request) {
String redirectPath = "/content/geometrixx/home.html";
if (StringUtils.isNotBlank(redirectPath)) {
getResponse().setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
getResponse().setHeader(redirectPath);
} else {
LOGGER.error("Redirect path is not set in component");
}
}
But the above code is failing. I believe it is due to "response already committed" error.
Can someone suggest me a way out for this problem?
I would suggest to you to not use a component on a page to do this. There is another mechanism called (Sling) Filter which is much more suited for something like this.
Put simply, a filter is a OSGi service that is called on every request. The filter gets the request and response passed and can use them to do different things, like for example check if a user visited a page before visiting another page.
There is already a good answer for something like this on StackOverflow: Filter request URL before any processing in CQ5.6
Important note:
Filters are only run if a users request gets to AEM. Typical AEM installations use a so called Dispatcher (Apache with a special "Dispatcher" Apache module) that cache responses. If a response is cached the Dispatcher will serve the cached HTML page instead of request AEM. So if a page is served from the Dispatcher cache your filter won't be run and therefore this check can not be done. There are a few ways to work around this but that's a topic for another question.
Sling filter is used when there is a need to handle more than one page following a certain pattern and you want to do some processing beforehand.
If you know the page URL already and simply want a redirect then you can also use sling:Mapping to redirect the page B request to page A.
You can use something like this.
Goto /etc/map/http and create a node below this path. For https requests, create a sling:folder for https as well.
/etc/map
+-- http
| +-- jcr:primaryType="sling:Folder"
+-- page-b
| +-- jcr:primaryType="sling:Mapping"
| +-- sling:redirect=/content/pageA.html -> Type String
| +-- sling:match=localhost.4502/content/pageB(.*)(/.*) -> Type String
+-- https
| +-- jcr:primaryType="sling:Folder"
+-- page-b
| +-- jcr:primaryType="sling:Mapping"
| +-- sling:redirect=/content/pageA.html -> Type String
| +-- sling:match=localhost.4502/content/pageB(.*)(/.*) -> Type String
Or if you simply want an internal handling of the resource and avoid page reload you can use:
jcr:primaryType="sling:Mapping"
sling:internalRedirect=/content/pageA.html -> Type String
sling:match=localhost.4502/content/pageB(.*)(/.*) -> Type String
To handle dispatcher redirect:
Include a rewrite rule in dispatcher for redirection from pageB to pageA.
Note: You can change the regex in sling:match to suit your needs.

URL Mapping in grails, should not be display anything except root name

i have created small grails project now i wanns work on url mapping
my project name is Hellograils
path is localhost:8080/Hellograils
i created user authentication and registration using rest api
now i wanna display in url only root path except that no want to display any controller or action name
eg : localhost:8080/Hellograils/userlogin/passwordcheck
insteatd of this url that should display only root path
i.e localhost:8080/Hellograils
if its not possible that should display like localhost:8080/Hellograils/users its should take only one word after root path how can i solve this one
eg : localhost:8080/Hellograils/userlogin/passwordcheck insteatd of
this url that should display only root path i.e
localhost:8080/Hellograils if its not possible that should display
like localhost:8080/Hellograils/users its should take only one word
after root path how can i solve this one
If your context root is Hellograils and you want the passwordcheck action in the userlogin controller to be associated with localhost:8080/Hellograils then you can do something like this in your url mappings:
"/"(controller: 'userlogin', action: 'passwordcheck')
If you want localhost:8080/Hellograils/user to be associated with that same action, you can do something like this:
"/user"(controller: 'userlogin', action: 'passwordcheck')
All of that assumes your controller name is UserloginController and the action name is passwordcheck. More common convention is to use camel case so your controller name would be UserLoginController and the action name would be passwordCheck. If you do use those names, then in the mapping you would need to use userLogin and passwordCheck instead of userlogin and passwordcheck.

Add a prefix to a bunch of urls

I have a bunch of routes with the same prefix:
# with prefixes
GET /api/v1.0/action1 controllers.Api.action1
GET /api/v1.0/action2 controllers.Api.action2
GET /api/v1.0/action3 controllers.Api.action3
GET /api/v1.0/action4 controllers.Api.action4
# normal urls
GET /action1 controllers.Home.action1
GET /action2 controllers.Home.action2
I want to get rid of repetition of /api/v1.0/. The urls must remain the same, I just want to not write them manually for each url in route file. In Rails it's possible. If there any way to do that?
Either you implement your own router for these actions following James Ropers' post, as mentioned by Rich. Doing so, allows you add the following to your route file:
-> /api/v1.0 YourPathBindableController
Alternatively you can use a plugin, such as navigator, which offers you advanced routing. Your navigator route file would then contain something like:
// Namespace ...
namespace("api"){
namespace("v1"){
GET on "index" to Application.index _
}
}
// ... or with reverse routing support
val api = new Namespace("api"){
val v2 = new Namespace("v2"){
val about = GET on "about" to Application.about _
}
}