Orbeon form in chinese returned with question marks - utf-8

I'm using ORBEON 2018.2.3.201905172253 PE within SAP Commerce (Hybris) on a Tomcat 7.0. When Hybris hits the Orbeon app to create a new form and get the inline HTML in Chinese, I'm getting question marks instead of Chinese characters.
URL: http://localhost:9001/orbeon/fr/yforms/myform/new?orbeon-embeddable=true&fr-language=zh-Hans
Method: GET
Headers:
[
{
"key":"hybris-Username",
"value":"-"
},
{
"key":"hybris-Group",
"value":"-"
},
{
"key":"hybris-Roles",
"value":"-"
},
{
"key":"Orbeon-Client",
"value":"portlet"
},
{
"key":"hybris-Proxy-09e4ff02-4715-4547-8f81-30082598eec9",
"value":"37bb0017-2675-4617-945d-6693bdae8eb9"
},
{
"key":"Content-Type",
"value":"text/html;charset=UTF-8"
}
]
I've found there's a known issue in Tomcat 7 for Chinese characters:
https://books.google.co.nz/books?id=kNVe8lzTec0C&pg=PA166&lpg=PA166&dq=webapp+http+request+chinese+question+marks&source=bl&ots=F11m7FJGYD&sig=ACfU3U1fufLJggVpnu4iUFT9SUJ6SdhqmA&hl=en&sa=X&ved=2ahUKEwjJq5L-_8njAhVi7nMBHXnMD0sQ6AEwAnoECAkQAQ#v=onepage&q=webapp%20http%20request%20chinese%20question%20marks&f=false
And apparently, Orbeon includes a way to set the character encoding to UTF-8 using the oxf.xforms.renderer.default-encoding param in the web.xml file:
https://doc.orbeon.com/xforms/filter
I already tried that in my web.xml and got the same results from the Orbeon app. I even executed the same request using Postman to check if it's an integration problem with my Hybris storefront, but the results were the same.
This is an excerpt of my web.xml:
<filter>
<filter-name>orbeon-xforms-filter</filter-name>
<filter-class>org.orbeon.oxf.servlet.OrbeonXFormsFilter</filter-class>
<!-- Uncomment this for the separate WAR deployment -->
<init-param>
<param-name>oxf.xforms.renderer.context</param-name>
<param-value>/orbeon</param-value>
</init-param>
<init-param>
<param-name>oxf.xforms.renderer.default-encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- End separate WAR deployment -->
</filter>
<filter-mapping>
<filter-name>orbeon-xforms-filter</filter-name>
<url-pattern>/xforms-jsp/*</url-pattern>
<!--Servlet 2.4 configuration allowing the filter to run upon forward in addition to request-->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Changing the url-pattern of the filter to "/orbeon/fr/yforms/*" broke the whole thing and I couldn't even render the form in English.
When debugging the request in Java I tried setting the Character Encoding of the HttpRequest object to UTF-8. Same results.
I've also tried these without good results:
• Set the URIEncoding attribute on the element in server.xml to URIEncoding="UTF-8".
• Set the useBodyEncodingForURI attribute on the element in server.xml to true.
Related to this:
Orbeon form localization using current site's session language
The answer to that thread explains how I'm localizing my forms.
THE WEIRDEST THING IS that the response of that URL DOES include some characters in Chinese: the label of the dropdown language selector. All other labels are question marks. Super weird!
I'd like to know how to fix this behaviour either changing my Tomat config or my Orbeon app config.
Thanks,
David

Well, as expected the problem was not related to Orbeon.
In my Spring Controller, the method that was getting my form from the database was annotated with a #ResponseBody. The String being returned by the Controller was in a perfect state containing the proper Chinese characters, but the response object was then intercepted by a Spring converter.
#RequestMapping(method = RequestMethod.GET, value = ...")
#ResponseBody
public String getFormDefinition(#PathVariable final String aaa, #PathVariable final String aaa,
#RequestParam(value = "document", required = false) final String aaa, final HttpServletResponse response)
throws ServletException, IOException, YFormServiceException
{
return "html content";
}
When there's a #ResponseBody annotation, the response is processed by Spring's message-converters. The default converters are listed here: https://www.baeldung.com/spring-httpmessageconverter-rest
One of those converters is the magical StringHttpMessageConverter. If you check its source code, you can see it uses ISO-8859-1 as a default charset. Every response processed by these converter is going to be encoded using ISO-8859-1, which does not support Chinese characters.
The Fix:
In my web spring config file I added:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg index="0" name="defaultCharset" value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
With register-defaults="false" you say to Spring not to use any of the default converters, but use the provided list below. When defining StringHttpMessageConverter, I specify UTF-8 (which supports Chinese characters) as the default encoding.
Et voila

Related

Spring Boot UTF-8 encoding issue. I suspect it tries to encode ISO-8859-1 to UTF-8

I'd like to use UTF-8 character encoding but I read somewhere that the controller's default encoding's ISO-8859-1.
I'm using spring boot with velocity.
So what I did, I tried to add the following ones (one at a time) to the header (None of them worked.)
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
Plus added to the application.properties the following lines:
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.velocity.charset=UTF-8
spring.velocity.content-type=text/html
server.tomcat.uri-encoding = UTF-8
I even tried to add the following line to the controller:
#RequestMapping(value = "/", method = RequestMethod.GET, produces={"text/html; charset=UTF-8"})
Plus tried to add the following bean to the application class:
#Bean
public HttpMessageConverter<String> responseBodyConverter() {
HttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
return converter;
}
This's a sample text that I included in the velocity template:
A sötét lovag igazi főhőse azonban valahogy ezúttal mégsem a mostanság nőnemű családtagjait szállodaszobábkban riogató Christian Bale, azaz a denevérember lett - hanem az ellenfél.
And that's the output I get:
A sötét lovag igazi fÅhÅse azonban valahogy ezúttal mégsem a mostanság nÅnemű családtagjait szállodaszobábkban riogató Christian Bale, azaz a denevérember lett - hanem az ellenfél.
Edit:
This's the controller I'm using currently:
#RequestMapping(value = "/", method = RequestMethod.GET, produces={"text/html; charset=UTF-8"})
public String homepage(Map<String, Object> model) {
return "homepage";
}
And I have a homepage.vm file at templates. Which has a header partial that contains this line:
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
Could be due to default Eclipse encoding?
Window -> Preferences -> General -> Workspace : Text file encoding
To resolve same problem, I have used VelocityConfigurer with the following bean definition:
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/pages/"/>
<property name="configLocation" value="/WEB-INF/velocity.properties"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="false"/>
<property name="prefix" value=""/>
<property name="suffix" value=".vm"/>
<property name="contentType" value="text/html; charset=UTF-8"/>
</bean>
Please note the contentType property set in viewResolver.
When first tried providing it via VelocityEngineFactoryBean, I have realised late that my properties file was ignored.
Also, in velocity.properties make sure you have:
input.encoding=utf-8
output.encoding=utf-8
I didn't need anything else in here for simple case.
In web.xml:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
That was it, I had no use for "produces" attribute in controller, no http meta needed, no xml charset encoding specified in the template file and no messing with messageconverter.
EDIT:
I don't have a playground setup with Spring Boot so can't test the exact implementation for you right now. However, web.xml here only defines a filter which can also be achieved programatically with Spring Boot:
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
#Component
public class MyFilter implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//action here
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void destroy() {}
}
I believe Spring Boot scans the sources for #Component automatically, otherwise package with filter's implementation should be added to component scan.
As for ideas on what the filter should do within doFilter(), you could explore the source code of Spring's CharacterEncodingFilter: https://github.com/spring-projects/spring-framework/blob/v4.2.1.RELEASE/spring-web/src/main/java/org/springframework/web/filter/CharacterEncodingFilter.java
Note that the above filter already extends other classes (such as OncePerRequestFilter).
I suppose you could instead add a method returning the filter instance:
#Bean
public Filter getCharacterEncodingFilter() {
org.springframework.web.filter.CharacterEncodingFilter characterEncodingFilter = new org.springframework.web.filter.CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return characterEncodingFilter;
}

Spring MVC XML result chunked, missing Content-length header

I have a bunch of web services that return some content, sometimes > 100kb.
Unfortunately for the bigger results, I get the partial response with Transfer-encoding: Chunked.
Is there any way to disable chunking?
That's my method:
#RequestMapping(value = "/form/{repository}/{objectId}", method = RequestMethod.GET, headers="()")
#ResponseBody
public FormHelper getFormConfig(HttpServletRequest req, HttpServletResponse resp, #PathVariable String repository,
#PathVariable("objectId") String objectId) throws Exception
And that's the Spring XML config:
<import resource="classpath*:context-aaa.xml" />
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="useDefaultSuffixPattern" value="false" />
</bean>
I had the same issue with Jersey library so I rewrote the project into Spring MVC, but it's still there...
Thanks in advance for any help.
Mariusz
I was able to make that work by adding the filter below:
<filter>
<filter-name>bufferFilter</filter-name>
<filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>bufferFilter</filter-name>
<url-pattern>/services/*</url-pattern>
</filter-mapping>
https://jira.spring.io/browse/SPR-11948

RequestMapping not working with multi-level URLs

I have a scenario where I'm making a simple get request through a link and my #RequestMapping configuration is not behaving as I'd expect.
Within an anchor tag I reference a url with the following pattern '/action-plan/export/pdf?token=xxx&taskId=1111&taskId=2222...'
Within my controller class I have this mapping at the class level:
#RequestMapping("/action-plan/export")
And this mapping at the method level
#RequestMapping(value="/pdf", method=RequestMethod.GET)
public String exportToPdf(#RequestParam("taskId") String[] taskIds,
#RequestParam("token") String[] encryptedEmplId, ModelMap model)
But every time I try this I get a 404 page not found error and the following Spring exception:
org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException: No matching handler method found for servlet request: path '/pdf', method 'GET', parameters map['taskId' -> array['1962326', '1962264', '1962317', '1962328', '1962324', '1962427', '1962325', '1962323', '1963147', '1962327', '1962318', '1962329', '1962330'], 'token' -> array['xxxx']]
I've noticed that when I remove the "/pdf?" portion of the link and remove 'value="/pdf"' from the method #RequestMapping it works fine. For the life of me I don't understand why adding /pdf to the url and RequestMapping is not working.
I think danny.lesnik's answer was pretty close but I'm writing my own answer so I can be more verbose.
I was working on a different project and figured out why the above doesn't work. In reference to my original question here is the relevant web.xml servlet mapping:
<servlet-mapping>
<servlet-name>spring-dispatcherServlet</servlet-name>
<url-pattern>/action-plan/export/*</url-pattern>
</servlet-mapping>
I noticed that whatever portion of the path I included in the of web.xml was not being included in the evaluation of RequestMapping values. I would have thought this bean configuration would have prevented that scenario (note the "alwaysUseFullPath" property):
<bean id="annotationHandlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="2"/>
<property name="alwaysUseFullPath" value="true"/>
</bean>
Maybe someone can shed some light on this detail for me.
In any case, thanks danny.lesnik
I recreated your problem and solved it by mapping servlet using .action extentions.
For example:
#Controller
#RequestMapping(value="/test")
public class DefaultController {
#RequestMapping(value="/pdf.action", method=RequestMethod.GET)
public ModelAndView indexView(#RequestParam("taskId") String[] taskIds,
#RequestParam("token") String[] encryptedEmplId){
ModelAndView mv = new ModelAndView("index");
return mv;
}
Spring XML mapping:
<context:annotation-config />
<context:component-scan base-package="com.vanilla.controllers" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
and this web.xml servlet mapping
<display-name>SpringMvcServlet</display-name>
<servlet>
<servlet-name>SpringMvcServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMvcServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
This code resolves this url
/test/pdf.action?token=3&token=4&taskId=4
flawless.

How to set content-type in Freemarker views when using Spring MVC?

I'm using Sping MVC with freemarker views. I set up a FreeMarkerViewResolver to resolve the views and it works so far but now I have encoding problems. All my views are HTML 5 pages in UTF-8 encoding and I also added a <meta charset="UTF-8" /> to the HTML page but characters are still printed in the wrong encoding. I checked the HTTP headers with curl and found this:
k#jules:~$ curl -I http://localhost:8080/testweb/test.view
HTTP/1.1 200 OK
Content-Type: */*;charset=ISO-8859-1
But when I request some non-existing resource (Which generates a Tomcat error) then I get this:
k#jules:~$ curl -I http://localhost:8080/testweb/nothere.html
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
So Tomcat itself returns the correct content-type but a Spring MVC Freemarker views don't.
For a JSP I can set the Content-Type in the JSP header but where can I set it for a freemarker template? I guess I have to do this somewhere in the Spring bean configuration but I can't find the right place.
The view resolver (should be in your dispatcher-servlet.xml) has a contentType property for that:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
</bean>
I have also experienced a problem with showing UTF-8 characters (special characters like æ. ø and å etc.), when using spring framework and freemarker template.
What i did was.
1. Ensure that your .ftl page is encoded with utf-8
This is an important thing to ensure, that a page not encoded with UTF-8 charset, could show the wrong numbers even though you have all the other requirements set. Check your IDE settings, to find out which default encoding it sets your files to. I think however today that both Eclipse and NetBeans set all files with UTF-8 encoding as standard. You must ensure that it is encoding UTF-8 with no BOM.
2. Include the Meta tag in your template file to set the charset
In your template (.ftl) file, which holds your <head> tag, set a <meta>, with the attribute charset="UTF-8". This is if you use HTML 5. If you use xhtml or HTML 4, your meta tag needs to look like this
HTML 5 <meta charset="UTF-8" />
HTML 4/XHTML <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
3. Make sure you set a Character Encoding Filter in your Deployment Descriptor File
You have to filter all incoming/outgoing requests through a character encoding filter. This filter is set in your deployment descriptor (web.xml / or the java equivalent WebApplicationInitializer).
WebApplicationInitializer (Java File)
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerCharacterEncodingFilter(servletContext);
}
/**
* Filter all incoming requests with character encoding UTF-8
* #param servletContext
*/
private void registerCharacterEncodingFilter(ServletContext servletContext) {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("characterEncodingFilter", encodingFilter);
characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
}
web.xml
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4. Set the FreeMarker Character Encoding in configurer and view resolver
You also need to make all your FreeMarker files be standard encoded with UTF-8, this is done by setting their properties to UTF-8 in the FreeMarkerConfigurer and the FreeMarkerViewResolver. This is set in your spring application context file (I will only show the Java equivalent as it is the same in the XML file).
/**
* FreeMarker Configurer will help configure different settings of
* the FreeMarker template engine.
*
* #return an object of the FreeMarkerConfigurer class.
*/
#Bean
public FreeMarkerConfigurer freemarkerConfig() {
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setTemplateLoaderPath("/templates/");
freeMarkerConfigurer.setDefaultEncoding("UTF-8");
return freeMarkerConfigurer;
}
/**
* The View resolver to use when resolving FreeMarker views.
*
* #return the View Resolver Object used to resolve FreeMarker views.
*/
#Bean
public FreeMarkerViewResolver viewResolver() {
FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver();
viewResolver.setPrefix("");
viewResolver.setSuffix(".ftl");
viewResolver.setCache(false); //Set to true during production
viewResolver.setContentType("text/html;charset=UTF-8");
return viewResolver;
}
Hope this helps you out :)

Can SpringMVC be configured to process all requests, but exclude static content directories?

If I map my spring application to process all incoming requests ('/*'), then requests for static content return 404's. For example, a request for "myhost.com/css/global.css" would return a 404, even though the resource exists as Spring intercepts the request.
The alternative is to map SpringMVC to a subdirectory (for example '/home/'), but in this case, you must pass this directory in all links within the application. Is there a way to map SpringMVC to '/' and exclude a set of directories from processing?
My current web.xml configuration is:
<servlet>
<servlet-name>springApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springApp</servlet-name>
<url-pattern>/home/*</url-pattern>
</servlet-mapping>
Idealy I would like to have the mapping be something like the following:
<servlet-mapping>
<servlet-name>springApp</servlet-name>
<url-pattern>/*</url-pattern>
<exclude>/css/*,/js/*</exclude>
</servlet-mapping>
Is this type of thing possible?
NOTE: this answer applies to Spring 3.0.4+ ONLY
(BTW, this question has also been dealt with here: Spring serving static content with mvc:resources, invalid xsd)
Check out the Spring mvc-showcase project in the Spring subversion samples repository. It shows exactly what you want to do, namely that you can delineate static resources which will not be processed by the DisapatcherServlet. See file /mvc-showcase/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml. Here's a snippet of how I handle these exclusions, where the JS, CSS, and images are in the app context root (with the MVC namespace mapped to mvc:
<!-- resources exclusions from servlet mapping -->
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/js/**" location="/js/" />
I solved by serving static content through the 'default' servlet, that just serve the content to the client. So my web.xml looks like this:
<servlet>
<servlet-name>MyApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyApp</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <!-- The 'dynamic' content -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping> <!-- The 'static' content -->
Hope this helps.
If you want to do this with Spring only, it's possible but a bit messy:
You'll either need to use a SimpleUrlHandlerMapping for which you can explicitly specify URL patterns which should be mapped to controllers OR extend it to support "ignore" URLs like "css/**".
You'll need to write your own HttpRequestHandler implementation that would basically consist of "getServletContext().getRequestDsipatcher().include()" call to return the requested resource as is.
You'll have to register that handler as defaultHandler for the above SimpleUrlHandlerMapping.
Once all that is done, all requests that can't be mapped to your controllers will be forwarded to your HttpRequestHandler and served "as is".
Simplest way for me (if using a late enough version of Spring) is
<mvc:resources mapping="/**/*.js" location="/"/>
<mvc:resources mapping="/**/*.css" location="/"/>
...
One way to do it would be with Filters. You'd have to write a little bit of custom code but it's not bad. Here's an example if you don't want to pass *.css or *.js files to your Spring servlet:
web.xml:
<filter-mapping>
<filter-name>fileTypeFilter</filter-name>
<filter-class>foo.FileTypeFilter</filter-class>
<url-pattern>/*</url-pattern>
</filter-mapping>
Java class:
public class FileTypeFilter implements Filter {
public void init(FilterConfig conf) {
// init logic here
}
public void destroy() {
// release resources here
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
if(shouldExclude(req)) {
chain.doFilter(req, res);
//some logic so the request doesnt go to the servlet
//maybe you could just forward
//the request directly to the file getting accessed. not sure if that would work
}
//file should be passed to the servlet; you can do some logic here
//if you want
}
private boolean shouldExclude(ServletRequest req) {
if(req instanceof HttpServletRequest) {
HttpServletRequest hreq = (HttpServletRequest) req;
return (hreq.getRequestURI().endsWith(".css") ||
hreq.getRequestURI().endsWith(".js"));
}
return false;
}
}
I haven't tested this, but I think it will work.
EDIT: There's isn't any exclude functionality in the servlet spec. I don't think there is a good way to do this within Spring, but it essentially achieves the same thing in your post.
EDIT 2: If you want to be able to easily change what gets filtered, you could just use Spring to inject something into the Filter at runtime.
EDIT 3: I just realized if you forward directly to the file, it'll do the filter again and you'll get caught in an infinite loop. There might be another way to do this with filters, but I'm honestly not sure what it is.
What are you using to serve your static images?
If it's Apache then you could configure Apache to not pass css/js requests to your app server.
If you are using Tomcat you'd put something like this in your httpd.conf:
JkUnMount /*.css webapp
Where 'webapp' is the entry from your workers.properties.
Sorry I can't give you a pure Spring solution, but this is how I do it.
I got the same problem and here is how I solved it:
The following was added to the web.xml file:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
<url-pattern>*.css</url-pattern>
<url-pattern>*.ico</url-pattern>
<url-pattern>*.png</url-pattern>
<url-pattern>*.jpg</url-pattern>
<url-pattern>*.htc</url-pattern>
<url-pattern>*.gif</url-pattern>
<url-pattern>*.html</url-pattern>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
The following was added to the spring3 MVC servlet bean definition file (such as applicationContext.xml, the file that is configured in web.xml as the contextConfigLocation.):
<mvc:annotation-driven />
<mvc:default-servlet-handler />
Do you have a consistent extension(s) for the requests you want processed by the Spring dispatcher (I believe most of the Spring examples use a *.htm)? In that case, you could map to the extensions you wish to have processed which would bypass your css and js files.
Otherwise I'd agree with Nalandial, the Filter approach is probably the best work around at this point.
I use virtual URL path to retrieve the resource I need. Typically I use Spring MVC, so I couldn't have javascripts and css under /WEB-INF/views folder. I came up with this custom servlet to ONLY allow access to .js & .css files within /WEB-INF/views folder. In your case, if you move the /css folder and /js folder to a parent folder such as /resource then my solution will be applicable to you.
You can change the String url = "YOUR_RESOURCE_FOLDER"
So for example, virtual path can be something like http://www.mysite.com/resources/path/path/app.js
That will map to my /WEB-INF/views/path/path/app.js
web.xml
<servlet>
<servlet-name>ResourceDispatcherServlet</servlet-name>
<servlet-class>mywebapp.web.ResourceDispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ResourceDispatcherServlet</servlet-name>
<url-pattern>/resource/*</url-pattern>
</servlet-mapping>
servlet
public class ResourceDispatcherServlet extends HttpServlet {
public void init() throws ServletException {
}
public void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
String servletPath = req.getServletPath(); // /resource
String pathInfo = req.getPathInfo(); // /path/path/app.js
String url = "/WEB-INF/views" + pathInfo;
String lastPath = StringUtil.substringAfterLast(pathInfo, "/");
String extension = StringUtil.substringAfterLast(lastPath, ".");
try {
RequestDispatcher dispatcher = null;
if (!StringUtil.isEmpty(extension) && ("js".equals(extension) || "css".equals(extension))) {
dispatcher = req.getRequestDispatcher(url);
}
if (dispatcher != null) {
dispatcher.include(req, rsp);
}
else {
rsp.sendError(404);
}
}
catch (Exception e) {
if (!rsp.isCommitted()) {
rsp.sendError(500);
}
}
}
}
If you are using Spring 3.0.4 and above you should use solution provided by atrain
Otherwise, you can do this simple thing:
perhaps you have following static directory structure you want to serve:
WebContent
|
WEB-INF
|
public
|
css
|
js
|
img
Eclipse Dynamic web projects by default generate following structure: WebContent/WEB-INF. Move the public folder out of your WEB-INF directory into WebContentdirectory.
On client side
refer your static files in following way:
<link rel="stylesheet" type="text/css" href="public/css/mystyles.css">
Here is my reference.
In my case everything was ok. But i have a problem in a Controller
that was my problem
#RequestMapping( method = RequestMethod.GET)
y change for this:
#RequestMapping(value = "/usuario", method = RequestMethod.GET)
and it works
look for a controller that has bad #RequestMappgin and change.
It's cleaner to use UrlRewriteFilter to redirect the request to your servlet, here an example of urlrewrite.xml
<urlrewrite>
<rule>
<from>^/img/(.*)$</from>
<to>/img/$1</to>
</rule>
<rule>
<from>^/js/(.*)$</from>
<to>/js/$1</to>
</rule>
<rule>
<from>^/css/(.*)$</from>
<to>/css/$1</to>
</rule>
<rule>
<from>^/(.*)$</from>
<to>/app/$1</to>
</rule>
<outbound-rule>
<from>/app/(.*)$</from>
<to>/$1</to>
</outbound-rule>
</urlrewrite>
NOTES:
It's important the last <rule> is in the bottom so img, js, css will be caught first
The <outbound-rule> is optional and is just to make the existing<c:url value="/app/some" /> render /some instead of /app/some
Usually, big websites prefer using another server only to handle static content.
Requests of static content goes to one server and dynamic goes to another (with spring, in this case).
In many cases, Nginx server (http://nginx.com/), a recent and very fast server.
But this is not trivial to do. A lot of configurations.

Resources