We're wanting to provide alternative PDF views as well as regular JSP views from our controllers and have added a ContentNegotiatingViewResolver and an XmlViewResolver to handle this.
All the examples I've found, including the Spring docs, return a simple view name, which the XmlViewResolver maps to a bean ID in its views.xml file ( in our case, a bean that writes PDF to the HttpResponse).
However we have our jsps organised in subfolders of the location defined in our InternalResourceViewResolver.
E.g.,
<bean id="viewResolver" class= "org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="2">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
So, from within our controller we return view names like "a/b/c" for a JSP that is in /WEB-INF/pages/a/b/c.jsp.
This works fine for JSPs, except that you can't have a bean id defined in views.xml as 'a/b/c'; it's not a valid bean ID.
We've investigated several options that either don't work are not satisfactory:
Put all JSPs in a single folder so that we can just use a bean-id-naming-compatible view name that can be resolved by an XmlViewResolver. This works but isn't ideal for organising our JSPs.
Have multiple InternalResourceViewResolver definitions using different prefixes. This just doesn't work; the first resolver of this type does not return null if it fails to find a matching view, it just fails with an exception and subsequent ViewResolvers are not used.
Use a separate controller method (or conditional code in the controller that returns the view name depending on what is the requested content type or URL suffix); these solutions seem to defeat the purpose of keeping a Controller ignorant of its views.
Try using wild-cards in the location property of XmlViewResolver; this fails with an exception.
I'm sure there is a nice elegant solution but it is eluding me just now. Is there a better approach such that I can return a view name like 'a/b/c' which has the potential to be resolved by an XmlViewResolver ?
Thank you for any suggestions.
Richard
Of course, bean aliases are the way to go...after a bit of digging around:
In the views.xml file targetted by XmlViewResolver:
<bean id="PdfView" class="com.blah.PdfDocView" />
<alias name="PdfView" alias="/a/b/structuredDocument"/>
which maps '/a/b/structuredDocument' to the PdfDocView bean.
Related
I'm finding it really difficult to find useful documentation on this. Basically I have two custom types 'Concept' and 'ConceptScheme' defined in my alfresco content model. Concept scheme has an association to many child concepts. Like this:
<type name="ancoat:conceptScheme">
<title>Concept Scheme</title>
<parent>ancoat:ddiObject</parent>
<associations>
<child-association name="ancoat:categories">
<source>
<mandatory>true</mandatory>
<many>false</many>
</source>
<target>
<class>ancoat:concept</class>
<mandatory>false</mandatory>
<many>true</many>
</target>
<duplicate>false</duplicate>
<propagateTimestamps>true</propagateTimestamps>
</child-association>
</associations>
<mandatory-aspects>
<aspect>ancoat:describedObject</aspect>
</mandatory-aspects>
</type>
I have two webscripts, one for creating the concept node, and one the concept scheme. I now want to create a webscript which takes some reference to each of those objects, and creates an association between them.
How do I do that? I've found the function Node.createAssociation, but I can't find any examples using it.
I would answer you the java way then.
Let's say that the namespace is http://ancoat.com/model/content/1.0 for the ancoat prefix have this association :
public static final QName ANCOAT_CATEGORIES_ASSOC = QName.createQName("http://ancoat.com/model/content/1.0",
categories);
Then you can associate one node to others with the node service :
getNodeService().setAssociations(pNode, ANCOAT_CATEGORIES_ASSOC, targets);
Where pNode is one node, and targets a list on nodes you want to do the association with.
Now, with a child association, it might be a better way to use the addChild method :
getNodeService().addChild(parentRefs, childRef, assocTypeQName, qname)
I'd like to use the Freemarker templating engine from within a controller's webscript to process some expression.
I've seen Alfresco provide the document.processTemplate("template content here") API.
The documentation says: "Executes a template from the repository against the current Document node"
Let's say I don't have any specific document to use, I just want to execute the templating engine and retrieve the output. What's the best way to do it?
Should I use some sort of temporary or "proxy" document? What's the easiest way to do so?
Not quite understandning what you are after here, I however think this is possible (not sure why anyone would like to do it though.)
You write your own class extending the BaseTemplateProcessorExtension, in that class you could write a method performing the stuff you want.
public class MyTemplateProcessorExtension extends BaseTemplateProcessorExtension {
public String myMethod(){
return "Hello World";
}
}
Declare it the following way in your spring config.
<bean id="templateHelper" parent="baseTemplateImplementation" class="my.alfresco.repo.template.TemplateHelper">
<property name="extensionName" value="templateHelper" />
</bean>
Then you can call it from your freemarker with:
${templateHelper.myMethod()}
The freemarker template calling "myMethod" should be a node in the repository (it should be possible to place it in the classpath as well, however I never had any success with this), since the processTemplate needs a nodeRef to the template itself.
Ok, please beware. I don't recommend this approach for anyone :)
I don't think it's possible to not use a document. So use a folder like data dictionary or create a dummy document with no content you always use.
The main purpose of alfresco is managing document.What kind of output you will produce without having value of any metadata of document in the template.This is the main reason behind this is not supported in alfresco, template engine is designed in such a way so that we can process any document.
I'm trying to dynamically register some spring beans in my ApplicationContext by using the ApplicationContextAware interface. I'm using the BeanDefitionBuilder to build the bean definitions and I register them with DefaultListableBeanFactory.registerBeanDefinition(). The bean I'm now trying to build would look like this in XML:
<bean id="compositeBean" class="SomeClass">
<property name="checks">
<list>
<ref bean="bean1"/>
<ref bean="bean2"/>
<ref bean="bean3"/>
</list>
</property>
</bean>
I have a list of BeanDefinitions for (bean1, bean2, bean3) above available. When I try to use
BeanDefinitionBuilder.genericBeanDefinition(SomeClass.class)
.addPropertyValue("checks", checks);
I end up with the error
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'compositeBean': Initialization of bean
failed; nested exception is
org.springframework.beans.ConversionNotSupportedException: Failed to
convert property value of type
'org.springframework.beans.factory.config.BeanDefinition[]' to
required type 'SomeClass[]' for property 'checks'; nested exception is
java.lang.IllegalStateException: Cannot convert value of type
[org.springframework.beans.factory.support.GenericBeanDefinition] to
required type [SomeClass] for property 'checks[0]': no matching
editors or conversion strategy found
How can programmatically add the list of bean references to my compositeBean?
Take a look at org.springframework.beans.factory.support.ManagedList
That's what <util:list/> uses to compile a list. Create a ManagedList as your variable "checks" and set that object as the property value.
I have an application that uses Spring+MyBatis and I have a Mapper interface to hold the SQL queries.
Mapper.java
package it.helloworld.mybatis;
import it.helloworld.dao.model.Numbers;
import java.util.List;
import org.apache.ibatis.annotations.Select;
public interface Mapper {
#Select("SELECT * FROM numbers")
List<Numbers> getNumbers();
}
I have used the MapperScannerConfigurer to use this Mapper as follows:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="it.helloworld.ibatis" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1" />
</bean>
I have used the name 'sqlSessionFactory1' because I have mutiple datasources in my application.
My question is:
I would like to change the interface to an XML file. Meaning I want to store my SQL query in an XML instead of an Interface. Can I configure MapperScannerConfigurer to do read SQL from an XML instead of an interface.? If yes, how.? If not, what should I use so as to make minimum code changes.?
Please check http://mybatis.github.io/spring/factorybean.html for more details on configuring your sqlSessionFactory1
The world has move on from MapperScannerConfigurer, then too let me answer this one. All you need in #MapperScan annotation.
I was asked this question in an interview. I said no then he asked then how do I access other portlet controllers. I am new to spring and what I know is that in application context file we have beans that are nothing but controllers and their corresponding dependencies...which are defined like below:
<bean id="projectProfileSummaryController" class="com.ca.beacon.implproject.controllers.ProjectProfileSummaryController">
<property name="restTemplateBuilder" ref="restTemplateBuilder"/>
<property name="implementProjectService" ref="implementProjectService"/>
along with their views that is defined in view resolver.
Am I right or wrong?
First of all, one portlet can have multiple controller classes.
Second of all, according to docs for FrameworkPortlet (parent class of DispatcherPortlet):
Passes a "contextConfigLocation" portlet init-param to the context instance, parsing it into potentially multiple file paths which can be separated by any number of commas and spaces, like "test-portlet.xml, myPortlet.xml". If not explicitly specified, the context implementation is supposed to build a default location from the namespace of the portlet.
So yes, one portlet can have multiple context xml files.