Spring Web Flow and Url Rewrite Filter - cleaning URLs - spring

I'm working on Spring MVC + Web Flow web application. I have mapped /home to MVC Controller and /test to Flow Controller. To remove /app from URLs i'm trying to use Url Rewrite Filter.
Mappings in MVC Controllers (#Controller) works good with that:
http://localhost:8080/spring/home -> render home view.
But when a request goes to WebFlow Controller something is wrong resulting in Error 404:
http://localhost:8080/spring/test -> redirect to http://localhost:8080/spring/app/test?execution=e1s1 -> page not found.
How to remove /app from URLs and got everything working ?
urlrewrite.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN" "urlrewrite3.0.dtd">
<urlrewrite default-match-type="wildcard">
<!-- to remove /app -->
<rule>
<from>/**</from>
<to>/app/$1</to>
</rule>
<outbound-rule>
<from>/app/**</from>
<to>/$1</to>
</outbound-rule>
</urlrewrite>
Dispatcher servlet mapping:
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Simple controller:
#Controller
public class MainController {
#RequestMapping(value={"/home", "/"})
public String index(Model model) {
return "index";
}
}
Some logs:
DEBUG [FlowHandlerMapping:108] : Mapping request with URI '/spring/app/test' to flow with id 'test'
DEBUG [FlowExecutorImpl:135] : Launching new execution of flow 'test' with input null
DEBUG [FlowDefinitionRegistryImpl:59] : Getting FlowDefinition with id 'test'
DEBUG [FlowExecutionImplFactory:78] : Creating new execution of 'test'
...
DEBUG [FlowExecutionImpl:417] : Assigned key e2s1
DEBUG [FlowHandlerAdapter:367] : Sending flow execution redirect to '/spring/app/test?execution=e2s1'
DEBUG [DispatcherServlet:824] : Null ModelAndView returned to DispatcherServlet with name 'spring': assuming HandlerAdapter completed request handling
DEBUG [DispatcherServlet:674] : Successfully completed request
DEBUG [DispatcherServlet:693] : DispatcherServlet with name 'spring' processing GET request for [/spring/app/app/test]
DEBUG [FlowHandlerMapping:114] : No flow mapping found for request with URI '/spring/app/app/test'
WARN [PageNotFound:947] : No mapping found for HTTP request with URI [/spring/app/app/test] in DispatcherServlet with name 'spring'

Temporarily i did it as here using customized FlowHandler. It works, but i think it must be a simpler solution...
package utils;
public class PrettyFlowUrlHandler extends DefaultFlowUrlHandler {
#Override
public String createFlowDefinitionUrl(String flowId, AttributeMap input, HttpServletRequest request) {
return cleanUrl(super.createFlowDefinitionUrl(flowId, input, request), request);
}
#Override
public String createFlowExecutionUrl(String flowId, String flowExecutionKey, HttpServletRequest request) {
return cleanUrl(super.createFlowExecutionUrl(flowId, flowExecutionKey, request), request);
}
protected String cleanUrl(String url, HttpServletRequest request) {
String pattern = request.getServletPath().substring(1) + "/";
return url.replaceFirst(pattern, "");
}
}
config:
<bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry"/>
<property name="flowUrlHandler">
<bean class="utils.PrettyFlowUrlHandler"/>
</property>
<property name="order" value="0" />
</bean>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>
<property name="flowUrlHandler">
<bean class="utils.PrettyFlowUrlHandler"/>
</property>
</bean>
Edit
Not working with custom flow handler like below:
#Component("test")
public class DataHandler extends AbstractFlowHandler {
#Override
public String handleExecutionOutcome(FlowExecutionOutcome outcome,
HttpServletRequest request, HttpServletResponse response) {
// ... checking outcome ...
return "/home"; // redirect to '404 page not found', because of rewrite to `/app/app/home`
}
}

Are you you trying to remove app from your url for eg
http://www.mydomain.com/app/home.html and change it to
http://www.mydomain.com/home.html
If yes then you should be configuring server.xml and your application should be deployed as ROOT instead of app in public_html/ or your tomcat directory.
This will work for you

Related

View not getting resolved in Spring mvc gradle application

web application is made with gradle sts project
i've added view Resolver like this
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".html" />
</bean>
it is hitting the url but wont return any view
#Controller
public class HomeController {
#RequestMapping(value = DatahubClientConstant.CLIENT_URL , method = RequestMethod.GET )
public ModelAndView getTestPage(HttpServletRequest request, HttpServletResponse response) throws Exception {
//System.out.println("Hello World");
return new ModelAndView("home");
}
}
Tried to sysout it works
It doesnt return any view?
After Some Research i have found out that InternalViewResolver does not resolve html pages directly that's why i was not able to get the view.
Spring MVC ViewResolver not mapping to HTML files
This was a helpful question in resolving the issue. All it is doing is loading the html as static content.

Spring MVC without annotation - HTTP 404 page not found error coming

I am trying to write a simple Spring MVC web application without using annotations. However, when I access specific URL, I am getting HTTP 404 error. The relevant code snippet is below:
web.xml changes done for front controller:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:web="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.4">
<display-name>POCProject</display-name>
<servlet>
<servlet-name>FrontController</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>FrontController</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
The servlet name is --> FrontController
Hence, have the following configuration file --> FrontController-servlet.xml
<beans ...>
<bean id="HandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/userdetails" class="com.example.controllers.UserDetailsController"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix"> <value>/WEB-INF/</value> </property>
<property name="suffix"> <value>.html</value> </property>
</bean>
</beans>
In above configuration file, the Handler mapping class is --> org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
The controller class for URL /userdetails is --> com.example.controllers.UserDetailsController
The code for this controller is below:
public class UserDetailsController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse res) throws Exception {
ModelAndView mw = new ModelAndView("userInfo");
return mw;
}
}
So, for a request with /userdetails the controller should send the view userInfo.html
However when I invoke this, I am getting HTTP 404 error.
I have deployed this in Apache tomcat, and the below is the message that I get in the tomcat console.
WARNING: No mapping found for HTTP request with URI [/POCProject/WEB-INF/userInfo.html] in DispatcherServlet with name "FrontController"
Any inputs on what I am missing here?
The javadoc for InternalResourceViewResolver says that it is a (emphasize mine):
Wrapper for a JSP or other resource within the same web application. Exposes model objects as request attributes and forwards the request to the specified resource URL using a RequestDispatcher.
A JSP is internally converted in a true servlet by Tomcat (or by any servlet container) that is a resource suitable for forwarding. But a simple HTML is not.
That means that Spring InternalResourceViewResolver cannot use HTML views and you must convert them to JSP files.

Set custom response in Spring interceptor

Here is my interceptor method where i want to set custom response to tell the UI what happened
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession(false);
if (session != null)
return true;
else{
response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT)
return false;
}
}
And in web.xml
<error-page>
<error-code>408</error-code>
<location>/error.html</location>
</error-page>
spring-servlet.xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<mvc:exclude-mapping path="/login" />
<bean class="com.example.CustomInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
When the session is timed out its not sending any response after return false.
Even the below is not working
response.sendRedirect("http://localhost:8080/home");
You can try very simple thing. Change your mvc:interceptros structure to
<mvc:interceptors>
<bean class="com.example.CustomInterceptor" />
</mvc:interceptors>
This essentially mean apply the interceptor to all applicable requests. I will come in a moment to why I say applicable in a moment. If above works then the issue is with your mapping.
Now as you know interceptors are configured at the level of HandlerMapping and it will be RequestMappingHandlerMapping (Spring 3.1+ with mvc:annotation-driven) or DefaultAnnotationHandlerMapping in your case.
Now as you have use <mvc:mapping path="/**" /> will map to all requests (including subpaths) as long as they are valid mappings. So lets say you have controller
#RequestMapping(value="/home", method = RequestMethod.GET)
public String welcome() {
return "welcome";
}
you cannot hit http://localhost:8080/yourProjectName/home/test and expect it to hit the interceptor. So you have to hit http://localhost:8080/yourProjectName/home as that is a valid HandlerMapping.
As to to response first debug if your interceptor is getting hit for any requests. If it does work then
response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT);
should redirect you to error.html as you have used
<error-page>
<error-code>408</error-code>
<location>/error.html</location>
</error-page>

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 mapping not working: PageNotFound

When i visit localhost:8080/home - i get:
WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/home] in DispatcherServlet with name 'appServlet'
When i visit localhost:8080/ or localhost:8080/index all look ok.
Why one path works, and another don't?
And thing, that confuse me: localhost:8080/homepage.html - return me my home view.
So my project here: https://github.com/IRus/jMusic
my web.xml
<!-- Base servlet handles all requests to the application. -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
servlet-context.xml - i using tiles
<annotation-driven/>
<resources mapping="/resources/**" location="/resources/"/>
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/"/>
<beans:property name="suffix" value=".jsp"/>
<beans:property name="order" value="1" />
</beans:bean>
<beans:import resource="controllers.xml"/>
<beans:import resource="tiles.xml" />
<beans:import resource="i18n.xml"/>
<beans:import resource="themes.xml"/>
tiles.xml
<bean id="tilesviewResolver" class="org.springframework.web.servlet.view.tiles2.TilesViewResolver">
<property name="order" value="0"/>
</bean>
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/views/tiles-definitions.xml</value>
</list>
</property>
</bean>
ErrorController
#Controller
public class ErrorController {
#RequestMapping("/403")
public String error403() {
return "403";
}
#RequestMapping("/404")
public String error404() {
return "404";
}
}
UserController
#Controller
public class UserController {
#Autowired
private UserService userService;
#RequestMapping("/")
public String index() {
return "redirect:/index";
}
#RequestMapping("/home")
public String home() {
return "home";
}
#RequestMapping("/login")
public String login() {
return "login";
}
#RequestMapping("/index")
public String listUsers(Map<String, Object> map) {
map.put("user", new User());
map.put("userList", userService.listUser());
return "user";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addUser(#ModelAttribute("user") User user,
BindingResult result) {
userService.addUser(user);
return "redirect:/index";
}
#RequestMapping("/delete/{idUser}")
public String deleteUser(#PathVariable("idUser") Long idUser) {
userService.removeUser(idUser);
return "redirect:/index";
}
}
Logs
Here: https://gist.github.com/IRus/2ac97c66070001247011
Interested moment in logs:
Mapped URL path [/homepage.html] into handler 'userController'
I added, and delete thats #RequestMapping in controller, but it still alive
I work in Idea 12.0.4
The problem was in the cache/IDE.
Class file is not updated when I deploy project.
First time i get trouble like this. Just restart IDE and clean tomcat webapps folder(delete my project files from here).
Now everything works as expected.

Resources