Spring MVC 3, Interceptor on all excluding some defined paths - spring-mvc

Is it possible to apply an interceptor to all controllers and actions, except some that are defined?
Just to be clear, I am not interested in applying an interceptor on a list of defined ones. I want to define those to exclude.
Thanks!

Since Spring 3.2 they added that feature with the tag
mvc:exclude-mapping
See this example from the Spring documentation:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/**"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor" />
</mvc:interceptor>
Here's the link to the doc

For java based configuration, from the docs
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}

When configuring an interceptor, you can specify a path pattern. The interceptor will be invoked only for controllers which the path matches the interceptor path pattern.
ref: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-config-interceptor
But as you probably noticed it, the path pattern doesn't support exclusion.
So I think the only way is to code a blacklist of paths inside the interceptor. When the interceptor is invoked, retrieve the HttpServletRequest.getRequestURI() and check if the path is blacklisted or not.
You can build the blacklist inside a #PostConstruct annotated method of the interceptor, and so get the blacklisted path from a property file for instance.

Related

Share config custom.xml for specific site in Alfresco

I don't want few aspects to be visible in manage aspect for a particular site. So I changed share config custom XML. But this change is being reflected for all sites. How can I make this specific for a site?
Any help is appreciated.
Thanks in advance!!!
You should use the concept of seperate share modules per site, using a site evaluator:
create a share-extension-mysitename-module.xml file in alfresco\site-data\extensions\ that looks like so:
<id>My site module</id>
<auto-deploy>true</auto-deploy>
<evaluator type="site.module.evaluator">
<params>
<sites>mysitename</sites>
<applyForNonSites>false</applyForNonSites>
</params>
</evaluator>
<customizations>
<customization>
<targetPackageRoot>org.alfresco</targetPackageRoot>
<sourcePackageRoot>com.mypackage</sourcePackageRoot>
</customization>
</customizations>
<configurations>
<config evaluator="string-compare" condition="DocumentLibrary" >
...
<aspects>
<visible>
<aspect name="my:visibleaspect" />
</visible>
</aspects>
</config>
</configurations>
</module>
</modules>
As far as I know, I don't think this is possible to have a custom share-config by site.
I see two (probably unsatisfying) solutions :
You can create your custom evaluator and use it to make some parts accessibles (or not).
<bean id="evaluator.doclib.action.siteBased" class="xx.xx.xx.web.evaluator.SiteBasedEvaluator">
<property name="sites">
<list>
<value>mysite</value>
</list>
</property>
</bean>
public class SiteBasedEvaluator extends BaseEvaluator {
private List<String> sites;
public SiteBasedEvaluator() {
super();
}
public SiteBasedEvaluator(String... pSites) {
super();
sites = Arrays.asList(pSites);
}
public boolean evaluate(JSONObject jsonObject) {
Boolean isFound = false;
if (sites != null) {
for (String site : sites) {
isFound = site.equals(getSiteId(jsonObject));
if (isFound) {
break;
}
}
}
return isFound;
}
You can deploy two share war in your tomcat, each one having the share-config-custom.xml you want

Spring Webflow: Can Validators Be Manually Set Per Flow?

I have multiple flow configured in my application:
<flow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" >
<flow:flow-location id="reservation1" path="/WEB-INF/flows/flow1.xml" />
<flow:flow-location id="reservation2" path="/WEB-INF/flows/flow2.xml" />
</flow:flow-registry>
These two flows use separate classes for their model attribute, call them Flow1DTO.java and Flow2DTO.java. However, they use a set of common JSPs/Tiles for their actual interface.
<form:form modelAttribute="reservationForm">
<!-- etc -->
</form:form>
Is it possible to define a separate Validator class per flow?
You can define a multiple validation methods for the same Model class for each specific view-state id. Where each custom validation method maps to a specific webflow view-state id.
Your validator class name for your model needs to be defined with the name "${model}Validator" (and have #Component annotation) and each validation method name needs to be named like this "validate${state} ([ModelClassType] model, ValidationContext context)"
So lets say you have a model class called "Reservation.java" and 2 different flows definition that use this model and each flow definition having a view-state definitions of
<!-- defined in your first flow file -->
<view-state id="ReservationSameDayViewState" view="sumting" model="reservationForm">
</view-state>
....
<!-- defined in your 2nd flow file -->
<view-state id="ReservationFutureViewState" view="sumting" model="reservationForm">
</view-state>
The validator class for Reservation model would like this:
#Component
public class ReservationValidator {
public void validateReservationSameDayViewState(Reservation reservation, ValidationContext context) {
// perform custom validation for first flow
}
public void validateReservationFutureViewState(Reservation reservation, ValidationContext context) {
// perform custom validation for 2nd flow
}
}
http://docs.spring.io/autorepo/docs/webflow/2.4.x/reference/html/views.html#view-validation-programmatic-validator
Also, it is bad practice to define your flows with integer increments. Change your flow registry definition to look like this. This way you don't have to keep manually adding flows to it every time you create new flows.
<flow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" base-path="/WEB-INF/flows">
<flow-location-pattern value="/**/*-flow.xml" />
</flow:flow-registry>
note: the flow names end with "-flow.xml". This is the unofficial standard way to define a flow-registry and flow names.
I figured out a solution that allowed me to validate multiple forms with a single implementation of a form validator.
The code looked something like this:
public void validateMethodName(Flow1DTO dto, ValidationContext context) {
valMethodName(dto, context);
}
public void validateMethodName(Flow2DTO dto, ValidationContext context) {
valMethodName(dto, context);
}
private void valMethodName(CommonFlowDTO dto, ValidationContext context) {
// do stuff
}
Putting validation methods in the DTO classes themselves was not an option. Validation required calls to the database, which would have coupled the DTO objects to the business logic and made the creation of the DTOs somewhat more complex.
I discovered that the validation methods could not specify an interface, leading to the duplicate methods for each concrete DTO class.

InternalResourceViewResolver to resolve both JSP and HTML together

I want org.springframework.web.servlet.view.InternalResourceViewResolver to resolve both JSP and HTML pages.
Is that possible?
You can configure an InternalResourceViewResolver something like this:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=""/>
</bean>
Where the WEB-INF/pages folder can contain both jsp and html pages and the suffix property is left empty.
Then in your controller, you can have methods that return html views and methods that return jsp views based on the suffix. For example, if index.html and index.jsp both exist in WEB-INF/pages you can do:
#RequestMapping("/htmlView")
public String renderHtmlView() {
return "index.html";
}
#RequestMapping("/jspView")
public String renderJspView() {
return "index.jsp";
}
However, as html pages are static and require no processing, you'd be better to use the <mvc:resources> tag rather than a view resolver for this type of page. See the docs for more info.

How to access subdir within images folder (getting 404)?

I've added a new subdir within my images folder and cannot get the new images to resolve.
Failed to load resource: ... 404 (Not Found)
http://localhost:8080/mywebapp/content/images/subdir/mysubdirimage.png
My directory structure:
src
-- main
--java
--webapp
--content
--images // <- these resolve
--subdir // <- new subdir...resolve fail for images
I have tried adding the following but does't work:
<mvc:resources mapping="/content/**" location="/content/" />
mvc-dispatcher-servelet.xml:
<mvc:annotation-driven/>
<mvc:default-servlet-handler />
<mvc:resources mapping="/content/**" location="/content/" /> //<-- Added this..no go!
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix"><value>/WEB-INF/views/</value></property>
<property name="suffix"><value>.jsp</value></property>
</bean>
You are halfway there with the mvc-dispatcher-servlet line you added, but you need to change it to:
<mvc:resources mapping="/images/**" location="/content/images/" />
Also try changing the method in your controller where you are attempting to access the images to something like:
#RequestMapping(value = "/staticImages", method = RequestMethod.GET)
public String showImage() {
return "/images/subdir/mysubdirimage.png";
}
And finally, with the example above try the URL (as you were doing above):
http://localhost:8080/mywebapp/images/subdir/mysubdirimage.jpg
You should also be able to access the images through the #RequestMapping pattern defined in your controller. For example, using the example I gave you above, you would enter the URL:
http://localhost:8080/mywebapp/staticImages

Default formView for SimpleFormController?

Firstly I would like to say that I am quite new to Spring (in particular the MVC framework), and just trying to understand how everything works so please go easy on me.
I'm playing around with a dummy application that I've created, and I've created a simple login form that users can access via the /login.html bean. The bean definition is as follows:
<bean name="/login.html" class="test.controller.LoginController">
<property name="successView" value="list_messages.html" />
<property name="commandClass" value="test.domain.Login" />
<property name="commandName" value="login" />
</bean>
(the Login class is a simple object containing a username and password field with appropriate getters and setters).
The LoginController class does virtually nothing for now:
public class LoginController extends SimpleFormController
{
#Override
protected ModelAndView onSubmit(Object command, BindException errors) throws Exception
{
return new ModelAndView(new RedirectView(getSuccessView()));
}
}
Now I have one view resolver in my bean definition file, which goes as follows:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
To support my Login form I have a login.jsp file in my jsp directory.
My question is as follows: why does accessing /login.html redirect me to login.jsp? I have not specified a formView property for my form, so how does the view resolver know to redirect me to login.jsp?
Thanks in advance for any help!
Joseph.
When you do not specify The logical view name, Spring relies on DefaultRequestToViewNameTranslator, which is installed by default. So if your request is something like
http://127.0.0.1:8080/app/<LOGICAL_NAME_EXTRACTED_BY_VIEW_NAME_TRANSLATOR_GOES_HERE>.html
Have you seen <LOGICAL_NAME_EXTRACTED_BY_VIEW_NAME_TRANSLATOR> ??? So if your request is
http://127.0.0.1:8080/app/login.html
The logical name extracted by ViewNameTranslator is login which is supplied To viewResolver and Translated To
/jsp/login.jsp
Nothing else

Resources