I started creating an application with Spring-Roo 1.3.1 and Spring-Security 3.1.7
I'm using Spring OpenEntityManagerInViewFilter to be able to do lazy loading of my domain objects.
<filter>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This is working fine so far. However, I encountered the following issue when doing a redirect from a controller:
#RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String update(#Valid Service service, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, service);
return "services/update";
}
uiModel.asMap().clear();
serviceRepository.save(service);
return "redirect:/services/" + encodeUrlPathSegment(service.getId().toString(), httpServletRequest);
}
This redirect return "redirect:/services/" + encodeUrlPathSegment(service.getId().toString(), httpServletRequest); is failing with an LazyInitializationException. It fails during execution of the filter chain after the commit is done and redirect took place. The URL redirected to is working when access directly.
When using return "forward:/services/" + encodeUrlPathSegment(service.getId().toString(), httpServletRequest); the page loaded just fine.
I really do not know why the hibernate session is not available when using "redirect". Another strange thing is, when activating DEBUG logging for org.springframework.security.web is is also working fine.
e.g. log4j.logger.org.springframework.security.web=DEBUG
I already searched the internet for some hints but generally lazy loading is working fine in my app, it's just in that circumstance and currently I do not fully understand why.
Any comments/hints are welcome.
Thanks
Stefan
Try to change controller like this:
#RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String update(#Valid Service service, BindingResult bindingResult,
Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, service);
return "services/update";
}
uiModel.asMap().clear();
Service attached = serviceRepository.save(service);
return "redirect:/services/" +
encodeUrlPathSegment(attached.getId().toString(),
httpServletRequest);
}
The instance service is create by Spring binder to map request values to the object but it is not attached to entityManager (no db session). When you call save you get an attached (instance managed by entityManager) instance so, if you try to get any lazy property from this instance it knows how do it.
You can found more information about JPA objects live cycle here.
Good luck!
Related
I created hello world example using Spring MVC, but there is one thing I didn't understand in servlet URL mapping, I did the following in web.xml:
<servlet>
<servlet-name>HelloWeb</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWeb</servlet-name>
<url-pattern>/test/*</url-pattern>
</servlet-mapping>
now if I want to call the following controller:
#Controller
#RequestMapping("/hello")
public class HelloWorld {
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model){
model.addAttribute("message","hello world");
return "index";
}
}
it will work using the following link:
http://localhost:8080/test/hello
but when I change the servlet url-pattern to "/*" and try:
http://localhost:8080/hello
it doesn't work, shouldn't it match my servlet ? as * matches everything
When you register a servlet with "/*" then it will override all the servlet mappings if there are any. Hence it should be avoided. This overrides default servlet mapping as well hence all default url handling also overridden and hence any specific url matching fails. In your case it is /hello.
With your case, initially you registered with /test/* this registered all your URL's with /test and hence they got identified.
It doesn't work for /* because, you have not registered/created a controller for that pattern.
It worked for http://localhost:8080/hello because, you have controller #RequestMapping("/hello")
Just change the RequestMapping to #RequestMapping("/") for url-pattern /*
I am having trouble with Turkish characters...In my JSP pages, there is no problem... but, when an alert come from Java side, Turkish character(ŞşİığĞüÜç...) seems like that (ı,?,ü,ç,Å,...)
In JSP pages, I use this code and ı can solve Turkish character problem
<%# page contentType="text/html;charset=UTF-8" language="java"%>
in Spring MVC config, I tried a lot of way but I didn't succeed... For example In my mvc config class, I set my MessageSource like that;
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
messageSource.setCacheSeconds(0);
return messageSource;
}
In this program, I try to reset password and I typed unregister email address..Finally I am getting exception and this following is exception code blog.
#Autowired
private MessageSource messages;
...
#ExceptionHandler({ UserNotFoundException.class })
public ResponseEntity<Object> handleUserNotFound(final RuntimeException exception, final WebRequest request) {
logger.error("404 Status Code", exception);
final GenericResponse bodyOfResponse = new GenericResponse(messages.getMessage("message.userNotFound", null, request.getLocale()), "UserNotFound");
return handleExceptionInternal(exception, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request);
}
In my messages_tr_TR.properties file,
...
message.userNotFound=Kullanıcı Bulunamadı
...
but In JSP pages this alert shows like that;
Kullanıcı Bulunamadı
How can I solve this problem..
Comment follow-up, you can set the encoding in your response header as well. An example if you're returning json would be
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "application/json; charset=utf-8");
return handleExceptionInternal(exception, responseHeaders, HttpStatus.NOT_FOUND, request);
In web.xml:
<jsp-config>
<!-- global JSP configuration -->
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<page-encoding>UTF-8</page-encoding>
</jsp-property-group>
</jsp-config>
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Put the actual text in the handler method (temporarily). Does it now look right? Is your messages file correctly saved as UTF-8? Also, I can't tell if you're using JSON or not...
Currently I have the following web.xml config:
<servlet>
<servlet-name>Website</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Website</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Server</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Server</servlet-name>
<url-pattern>/server/</url-pattern>
</servlet-mapping>
As for two example controllers:
#Controller
public class ApiRequests {
protected final Logger logger = Logger.getLogger(ApiRequests.class);
#RequestMapping(value = "api.json", produces = {"application/json"}, method = RequestMethod.GET)
#ResponseBody
public String handleActionJson(final HttpServletRequest request){
return "{test: 'blaat'}";
}
}
And
#Controller
#RequestMapping("/")
public class IndexController {
#RequestMapping("*.html")
public void showIndex(){
}
}
Now my problem is that when I try to call the /server/api.json url, the server won't give the json response, instead it gives me the following error:
PageNotFound:1108 - No mapping found for HTTP request with URI [/WorldDefense/server/api.json] in DispatcherServlet with name 'Website'
Which basically means its trying to search for /server/api.json in the Website servlet instead of the Server serlvet, as for my question: would it be possible to get this setup to work? (So /server/ to map to the Server servlet and all the other url combinations to the Website servlet)
Edit 1
I updated the code to reflect the changes as suggested by Costi Ciudatu but it still doesn't work. I removed the #RequestMapping("/server") and now only have the #RequestMapping at the handleActionJson method. Both resulting in these errors:
10:57:26,046 WARN PageNotFound:1108 - No mapping found for HTTP request with URI [/WorldDefense/server/server/api.json] in DispatcherServlet with name 'Website'
10:57:40,509 WARN PageNotFound:1108 - No mapping found for HTTP request with URI [/WorldDefense/server/api.json] in DispatcherServlet with name 'Website'
Mappings according to the tomcat log:
Server-servlet
11:03:49,655 INFO RequestMappingHandlerMapping:178 - Mapped "{[/api.json],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public java.lang.String com.world2.worlddefense.server.controllers.ApiRequests.handleActionJson(javax.servlet.http.HttpServletRequest)
11:03:50,125 INFO RequestMappingHandlerMapping:178 - Mapped "{[/api.json],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public java.lang.String com.world2.worlddefense.server.controllers.ApiRequests.handleActionJson(javax.servlet.http.HttpServletRequest)
Website-servlet
11:03:50,380 INFO RequestMappingHandlerMapping:178 - Mapped "{[//*.html],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public void com.world2.worlddefense.website.controllers.IndexController.showIndex()
11:03:50,381 INFO RequestMappingHandlerMapping:178 - Mapped "{[/login],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.world2.worlddefense.website.controllers.TempTestController.showTest()
You can define multiple DispatcherServlets in the same web.xml and map them as you wish. However, the servlet mapping should not be reflected in the #RequestMapping of your controllers. Your controllers always map to paths relative to the servlet mapping; in your case, I think you could get that JSON response if you tried /WorldDefence/server/server/api.json...
If you want different controllers to be associated with the two dispatchers, you only need to make sure that the proper controllers are loaded in the corresponding application context: Website-servlet.xml and Server-servlet.xml in case you stick with this convention.
Long story short, your mapping for ApiRequests should be '/', not '/server' and that controller should only be included in the "Server" dispatcher context.
As a side note, since 3.2.x, the .json extension is handled by the ContentNegotiationManager, so your controller should return some domain object which will be transparently marshaled by the Spring HttpMessageConverter mechanism and will thus be able to produce media types other than JSON with no effort.
Starting my way with STS and created a new basic "Hello World" Spring MVC project.
I wanted to add a filter to my app so I created a filter (HelloWorldFilter.java) with the following doFilter method:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("Entering Filter");
request.setAttribute("hello", "Hello World from HelloWorldFilter!");
chain.doFilter(request, response);
System.out.println("Exiting HelloWorldFilter");
}
According to what I read it (my filter) should also be defined in the application context as a spring bean (Spring delegates it to my filter - from this manual )
So in my application context I have:
<bean id="helloWorldFilter" class="com.yl.mvc.filters.HelloWorldFilter"> </bean>
My web.xml contains the following:
<filter>
<display-name>HelloWorldFilter</display-name>
<filter-name>HelloWorldFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>HelloWorldFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
In my .jsp file I added:
<P><%=request.getAttribute("hello")%></P>
But all I see in my web-page is null (I expected Hello World from HelloWorldFilter!).
The filter doesn't even get invoked..
Am I missing something here?
Thanks in advance,
Yogi
Ok go it solved.
The filter (which is a spring bean) must have the same name in the bean definition (in the application context) as that in the filter-name element (in the web.xml).
In my case I had in my application context:
<bean id="helloWorldFilter"...
and in my web.xml:
<filter-name>HelloWorldFilter</filter-name>
So once it is with a capital H and once a small h - which caused the issue.
To resolve it I simply changed the bean id in my application context to HelloWorldFilter.
I have a Spring app that is working correctly except for how it deals with foreign language characters that need to be included in the redirect url when the controller redirects the user.
If the controller redirects the user to the following URL, for example, it will fail:
http://localhost:8080/diacritic/تشكيل
You need to re-encode the redirection target.
I have code like this:
String encodedId = URLEncoder.encode("中文", "UTF-8");
ModelAndView m = new ModelAndView(new RedirectView("/view/" + encodedId, true, true, false));
return m;
This worked for me.
The path variable is decoded in ISO-8859-1. There are two things you can do to get around this.
To see the actual UTF-8 decoded characters on the server, you can just do this and take a look at the value (you need to add "HttpServletRequest httpServletRequest" to your controller parameters):
String requestURI = httpServletRequest.getRequestURI();
String decodedURI = URLDecoder.decode(requestURI, "UTF-8");
You can then do whatever you want, now that you have the right data on the server.
You can also try adding a filter to your web.xml file.
<filter>
<filter-name>CharacterEncodingFilter</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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>