Multiple serveResource methods in liferay mvc portlet - liferay-7

How can i Do multiple serveResource methods in normal liferay mvc portlet(i know in spring mvc )
give me any example if you have.
Thank you

Step 1: Add the below code in JSP
<portlet:resourceURL id="/server/resource/one" var="oneURL" />
<portlet:resourceURL id="/server/resource/two" var="twoURL" />
Step 2: Create Class and implement "MVCResourceCommand"
#Component(
immediate = true,
property = {
"javax.portlet.name=your_portlet_name_YourPortlet",
"mvc.command.name=/server/resource/one"
},
service = MVCResourceCommand.class
)
public class YourMVCResourceCommand implements MVCResourceCommand {
// your resource handling code
}
The property "mvc.command.name" to the value of the id property in your JSP’s must be match.
Check this link for more infromation: https://help.liferay.com/hc/en-us/articles/360018159491-MVC-Resource-Command

Related

What is the right way to get Page object via Sling Model annotation

I have a property with the path to required page in a content file
...
<some_block
...
sling:resourceType="some_path_to_some_component"
somePage="some_path_to_page"
.../>
...
suitable HTL component some-component.html
<div data-sly-use.some_model="org.example.SomeModel">
...
</div>
and model class SomeModel.java
package org.example;
...
import com.day.cq.wcm.api.Page;
...
#Model(adaptables = { SlingHttpServletRequest.class, Resource.class },
defaultInjectionStrategy = DefaultInjectionStrategy.REQUIRED)
public class RelatedContentBlock {
#ValueMapValue
private Page somePage;
...
}
I easily can get the required Page object using #Inject and #Via annotations, but why can't I grab it with the #ValueMapValue annotation? I tried to use all the possible variants including via attribute and so on. And yes, I can get it from the pageManager, but what's wrong with #ValueMapValue?
Thanks in advance!
The documentation that you linked of the #ValueMapValue annotation has the answer you are looking for:
Annotation to be used on either methods, fields or constructor parameter to let Sling Models inject a value from the ValueMap of the current resource.
The important part is:
inject a value from the ValueMap
A Page is not a ValueMap. Therefore, this annotation can not be used to inject a page.
This annotation is mainly used to inject page properties. Because page properties (or resource properties for that matter) are stored in a ValueMap. That is why you can use the #ValueMapValue annotation to inject the jcr:title of a page:
#ValueMapValue(name = "jcr:title")
private String title;
This is equivalent to (pseudo code):
final ValueMap pageProperites = Page.getProperties();
final String title = pageProperties.get("jcr:title", "" /* default */);

Grails 3 Restful Link Generator (w/o the action)

Is there a way to reconfigure the Grails 3 Link Generator to create Restful links, i.e. localhost:8080/book/{id} rather than the old style that includes the action in the URL, localhost:8080/book/show/{id}?
I'd like to have restful URLs in the location headers of the responses to save actions.
I've been using this Grails Restful Link Generator as a workaround. I'm not perfectly happy with it, but it's the best I've been able to come up with thus far.
1. Create a trait in src/main/groovy that removes the superfluous action from the URL
import grails.web.mapping.LinkGenerator
trait RestfulLinkGeneratorTrait {
LinkGenerator grailsLinkGenerator
String generateLink(Map map) {
map.controller = map.controller ?: this.controllerName
map.absolute = map.absolute ?: true
map.action = map.action ?: "show"
grailsLinkGenerator.link(map).replace("/$map.action", "")
}
}
2. Implement the RestfulLinkGenerator on your controller(s) and call generateLink(id: obj.id) to generate links.
#Secured('ROLE_USER')
class BookController extends RestfulController implements RestfulLinkGeneratorTrait {
//... other methods ...//
#Transactional
def save() {
// ... save you resource ... //
response.addHeader(HttpHeaders.LOCATION, generateLink(id: book.id))
respond book, [status: CREATED, view: 'show']
}
//... other methods ...//
}

OData include "Custom Properties" added to Entity Framework models via Partial Classes

I made a partial class file to add new properties to my Entity-Framework generated model.
I am using WebAPI + OData, and the $metadata doesn't list my new/custom properties, and so the JSON it returns doesn't include my new/custom properties.
For example, let's say my Entity is "Person"
"Person" has one Database property; NumSpouses; an int which is returned in $metadata like this:
<Property Name="NumSpouses" Type="Edm.Int32"/>
That's great, but I added a property like this to a separate file, with a partial class:
public partial class Person {
...
public string MarriedStatus {
get { return this.NumSpouses==0 ? "Single" : "Married"; }
}
...
}
How can I get this Property available in my OData responses?
<Property Name="MarriedStatus" Type="Edm.String"/>
Currently, if I asked for MarriedStatus in $expand (as if it were a NavigationProperty.... which it's not [I thought I'd try $expand anyway as if it magically provided custom properties]), I'd get a message like this:
{
"odata.error":{
"code":"","message":{
"lang":"en-US","value":"The query specified in the URI is not valid. Could not find a property named 'MarriedStatus' on type 'fakeDataModels.Person'."
},"innererror":{
"message":"Could not find a property named 'MarriedStatus' on type 'fakeDataModels.Person'.","type":"Microsoft.Data.OData.ODataException","stacktrace":" at ..."
}
}
}
MarriedStatus is a calculated/readonly property. The ASP.NET implementation of OData does not currently support such properties. As a workaround, add a setter that throws NotImplementedException.
public string MarriedStatus {
get { return this.NumSpouses > 0 ? "Married" : "Single"; }
set { throw new NotImplementedException(); }
}
Optionally, if you are using OData V4, you can annotate MarriedStatus to specify that it is calculated. See Yi Ding's answer to OData read-only property. But the annotation is advisory only; it does not prevent clients from attempting to set a calculated property (e.g., in a POST request).
In addition to the answer of lencharest. You should use the Ignore() function of the Entity Framework fluent API instead of the [NotMapped] attribute. Because OData looks for this attribute to ignore properties for serialization. If you use the fluent API you will not have this problem.
dbModelBuilder.Entity<TEntity>()
.Ignore(i => i.ComputedProperty);

how to change the themes in asp.net mvc 2

I would like to have an option wherein a user can choose his theme for the site from the dropdown list and the theme applies to that page [atleast].
I want this to be done in ASP.NET MVC 2 without using jquery like frameworks.
How can this be accomplished.
I am using the default webforms viewengine and donot want to go for a custom viewengine for this purpose.
It seems this is not supported out of the box, but here's what I did to implement theming:
First, I Added the App_Themes folder to my project, and set up a couple of themes
I then decided to try and mimic the Web-forms profile provider as close as possible, and added a profile-property to web.config:
<profile>
<properties>
<add name="ThemePreference" type="string" defaultValue="Blue" />
</properties>
</profile>
So, basically what I wanted to do was to be able to load the different css's from the appropriate theme-folder when the theme changed. I did this by implementing a helper method attached to the UrlHelper class so that I could write:
<link href="#Url.Theme("~/Content/Site.css")" rel="stylesheet" type="text/css" />
This should then load the appropriate themed Site.css, and fall back to ~/Content/Site.css if no file was found.
The helper is pretty simple:
public static class UrlHelpers
{
public static string Theme(this UrlHelper url, string u)
{
if (u.StartsWith("~")) u = u.TrimStart('~');
SettingsProperty settingsProperty = ProfileBase.Properties["ThemePreference"];
return url.Content("~/App_Themes/"+settingsProperty.DefaultValue + u);
}
}
Now, in this version of the code it simply gets the default-value, so you'll need to tweak the code slightly. But as you can see, this is not limited to css-files, but works with everything from .master files to images.
Update - Using Session instead of profile
public static class UrlHelpers
{
public static string Theme(this UrlHelper url, string u)
{
if (u.StartsWith("~")) u = u.TrimStart('~');
object currentThemeName = null;
if (url.RequestContext.HttpContext.Session != null)
{
currentThemeName = url.RequestContext.HttpContext.Session["ThemePreference"];
}
return currentThemeName != null ? url.Content(String.Format("~/App_Themes/{0}{1}", currentThemeName, u)) : url.Content("~"+u);
}
}
The return-line in this method checks if it found a ThemePreference session-value, and then returnes the appropriate URL for the content requested, otherwise it simply returns the content as it was requested with no App_Theme prefix.
In your controlleraction for the DropDown postmethod, you'd simply do:
Session.Add("ThemePreference", whateverValueYouGotFromDropdown);
Update ends
With some tweaking and fixing, this should do the trick.
Hope it helps some, even though it's not a complete walkthrough :)

Dependency Injection & Model Binding (ASP MVC, Autofac), When to use what?

This is more like a conceptual question. When to use Model Binding (in ASP.NET MVC Framework) and when to inject objects using IoC (lets say Autofac here) ?
One specific scenario is like lets say, I have the following action method
public ActionResult EditProfile(string UserId)
{
// get user object from repository using the the UserId
// edit profile
// save changes
// return feedback
}
In the above scenario, is it possible to inject a user object to action method such that it automatically gets the user object using the UserId ? The resulting signature being:
public ActionResult EditProfile(UserProfile userObj) //userObj injected *somehow* to automatically retreive the object from repo using UserId ?
Sorry if it all doesn't makes sense. It`s my first time using IoC.
EDIT:
This is the way to do it > http://buildstarted.com/2010/09/12/custom-model-binders-in-mvc-3-with-imodelbinder/
You can do what you need using a custom action filter. By overriding OnActionExecuting, we have access to the route data, and the action parameters of the action that will be executed. Given:
public class BindUserProfileAttribute : ActionFilterAttribute
{
public override OnActionExecuting(FilterContext filterContext)
{
string id = (string)filterContext.RouteData.Values["UserId"];
var model = new UserProfile { Id = id };
filtextContext.ActionParameters["userObj"] = model;
}
}
This attribute allows us to create the parameters that will be passed into the action, so we can load the user object at this point.
[BindUserProfile]
public ActionResult EditProfile(UserProfile userObj)
{
}
You'll probably need to get specific with your routes:
routes.MapRoute(
"EditProfile",
"Account/EditProfile/{UserId}",
new { controller = "Account", action = "EditProfile" });
In MVC3 we get access to the new IDepedencyResolver interface, which allows us to perform IoC/SL using whatever IoC container or service locator we want, so we can push a service like a IUserProfileFactory into your filter, to then be able to create your UserProfile instance.
Hope that helps?
Model binding is used for your data. Dependency injection is used for your business logic.