Jersey #BeanParam, #HeaderParam alternatives in Spring mvc - spring-mvc

In Jersey we can inject a list of headers to a model class using #BeanParam and #HeaderParam. Are there any alternatives in Spring MVC to do the same thing?
I know in spring-MVC, we can inject all headers to a map **#RequestHeader Map<String, Object> headers** and extract the fields from there. But I was wondering if I can inject my required headers into a model class.
Thanks in advance.

Replacement for #HeaderParam is Spring MVC's #RequestHeader
The #RequestHeader annotation allows a method parameter to be bound to a request header.
#RequestMapping
public void displayHeaderInfo(#RequestHeader("Accept-Encoding") String encoding,
And #BeanParam you don't need special annotation, just add your bean to method as is:
#RequestMapping
public String displayHeaderInfo (MyBean myBean) {

Related

StrictHttpFirewall in spring security 4.2 vs spring MVC #MatrixVariable

Having upgraded to spring security 4.2.4 I discovered that StrictHttpFirewall is now the default.
Unfortunately it doesn't play well with spring MVC #MatrixVariable since ";" are not allowed anymore.
How to get around that?
Example:
#GetMapping(path = "/{param}")
public void example(#PathVariable String param,
#MatrixVariable Map<String, String> matrix) {
//...
}
This could be called like this:
mockMvc.perform(get("/someparam;key=value"))
And the matrix map would be populated.
Now spring security blocks it.
org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL contained a potentially malicious String ";"
at org.springframework.security.web.firewall.StrictHttpFirewall.rejectedBlacklistedUrls(StrictHttpFirewall.java:140)
I could use a custom HttpFirewall that would allow semicolons.
Is there a way to use #MatrixVariable without using forbidden characters?
BTW: the javadoc is incorrect https://docs.spring.io/autorepo/docs/spring-security/4.2.x/apidocs/index.html?org/springframework/security/web/firewall/StrictHttpFirewall.html
Since:
5.0.1
I guess it was backported?
You can dilute the default spring security firewall using your custom defined instance of StrictHttpFirewall (at your own risk)
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
firewall.setAllowSemicolon(true);
return firewall;
}
And then use this custom firewall bean in WebSecurity (Spring boot does not need this change)
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
// #formatter:off
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
...
}
That shall work with Spring Security 4.2.4+, but of-course that brings some risks!
As mentioned by Крис in a comment if you prefer to use a XML approach, you can add the following part to your securityContext.xml (or whatever your spring-security related xml-config is called):
<bean id="allowSemicolonHttpFirewall"
class="org.springframework.security.web.firewall.StrictHttpFirewall">
<property name="allowSemicolon" value="true"/>
</bean>
<security:http-firewall ref="allowSemicolonHttpFirewall"/>
The <bean> part defines a new StrictHttpFirewall bean with the id allowSemicolonHttpFirewall which is then set as default http-firewall in the <security> tag by referencing the id.
I used combination of following two
https://stackoverflow.com/a/48636757/6780127
https://stackoverflow.com/a/30539991/6780127
First one resolved the
The request was rejected because the URL contained a potentially malicious String ";"
Second one Resolved the
Spring MVC Missing matrix variable
As I am using Spring Security with Spring Web I had to do both And the issue is now Resolved.
I found using #MatrixVariable Following Pattern is useful. First in Url {num} has to be mentioned to use it as #MatrixVariable
#RequestMapping(method = RequestMethod.GET,value = "/test{num}")
#ResponseBody
public ResponseEntity<String> getDetail(#MatrixVariable String num){
return new ResponseEntity<>("test"+num, HttpStatus.OK);
}

How to use "RestController" and "Controller" in an application

1) Using Controller at SingleFileUploadController, gives correct result in jsp and when used RestController instead of Controller in SingleFileUploadController, it is not directing to jsp. Why?
2) Is it possible to use both at same time?
reference:
http://memorynotfound.com/spring-mvc-file-upload-example-validator/
Thanks
Harshal
Because RestController is for controllers who don't forward to views. Their return value is sent as the response body.
Yes, it's possible to have Controllers and RestControllers in the same webapp. If you want some methods of your controller to return views, and some others to return response bodies (i.e. act as in a RestController), then use #Controller, and annotate your "REST" methods with #ResponseBody.
To answer the question in regards to #Controller and #RestController being together.
First controller:
#RestController //specify that this class is a restful controller
#RequestMapping("/api")
public class RestHomeController {
Second Controller
#Controller //specify that this class is a controller
#RequestMapping("/")
public class HomeController {
#Controller tells the api to return ModelAndView Object which contains the name of your view hence the jsp file to view, while #RestController returns serialized response.
No you cannot have them both, controller is either annotated with one of them but as #JB Nizet mentioned you can use #Controller and #ResponseBody to achieve the functionality for #RestController for specific API , anyway this was the trend used since the support for RestController was not there before spring 4.

How to test Spring HandlerInterceptor Mapping

I am implementing a HandlerInterceptor that needs to execute business logic prior/after requests to several paths are handled. I want to test the execution of the Interceptor by mocking the request handle lifecycle.
Here is how the interceptor is registered:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/test*"/>
<bean class="x.y.z.TestInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
I want to test not only the preHandle and postHandle methods, but the mapping to the path as well.
The following test can be written with the help of JUnit and spring-test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:META-INF/spring.xml", ... })
public class InterceptorTest {
#Autowired
private RequestMappingHandlerAdapter handlerAdapter;
#Autowired
private RequestMappingHandlerMapping handlerMapping;
#Test
public void testInterceptor() throws Exception{
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/test");
request.setMethod("GET");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain handlerExecutionChain = handlerMapping.getHandler(request);
HandlerInterceptor[] interceptors = handlerExecutionChain.getInterceptors();
for(HandlerInterceptor interceptor : interceptors){
interceptor.preHandle(request, response, handlerExecutionChain.getHandler());
}
ModelAndView mav = handlerAdapter. handle(request, response, handlerExecutionChain.getHandler());
for(HandlerInterceptor interceptor : interceptors){
interceptor.postHandle(request, response, handlerExecutionChain.getHandler(), mav);
}
assertEquals(200, response.getStatus());
//assert the success of your interceptor
}
HandlerExecutionChain is populated with all the mapped interceptors for the specific request. If the mapping is failing, the interceptor will not be present in the list and hence not executed and the assertion at the end will fail.
The Spring Framework provides dedicated support for testing your Spring MVC configuration and components in the form of the Spring MVC Test Framework, available since Spring Framework 3.2 (and as a separate spring-test-mvc project since Spring Framework 3.1).
In the first link you will find numerous examples of how to use the Spring MVC Test framework. In addition, you will also find slides by Rossen Stoyanchev (author of the Spring MVC Test Framework) in our Spring 3.1 and MVC Testing Support and Testing Web Apps with
Spring Framework 3.2 presentations from SpringOne 2GX.
I'm confident those resources should help you get your tests written concisely, but if you still need help, feel free to post back here.
Regards,
Sam (author of the Spring TestContext Framework)

creating and access properties file in spring mvc

read this article on SO, and had some clarifying questions.
I put my config.properties under src/main/resources
In spring-servlet.xml config file
I added the following:
<context:property-placeholder location="classpath:config.properties"/>
In my business layer, I am trying to access it via
#Value("${upload.file.path}")
private String uploadFilePath;
Eclipse shows error:
The attribute value is undefined for the annotation type Value
Can i not access the property in the business layer or are property files only read in the controller?
UPDATE::
src/main/java/com.companyname.controllers/homecontroller.java
public String home(Locale locale, Model model) {
MyServiceObject myObj = new MyServiceObject();
System.out.println("Property from my service object: = " + myObj.PropertyValue());
if(myObj.PerformService())
{
///
}
}
src/main/java/com.companyname.services/MyService.java
public class MyServiceObject {
#Value("${db.server.ip}")
private String _dbServerIP;
public String PropertyValue() {
return _dbServerIPaseURL;
}
}
Another site where I found the explanation
Please check that you import Value from org.springframework.beans.factory.annotation package:
import org.springframework.beans.factory.annotation.Value;
also the property placeholder must be declared in the respective context configuration file, in case of controller it's likely Spring dispatcher servlet configuration file.
update You are confusing property-placeholder that post processes bean values, that contain dollar symbol ${<property name>} with Spring expression language container extension that process values containing a hash symbol #{<Spring expression language expression>}, in the link you have shown the latter approach is used.
regarding the instantiation of MyServiceObject myObj
If you want the object to be managed by Spring you should delegate its creation to the container:
if MyServiceObject is a stateless service then it's a singleton with the singleton bean scope, you should register it in your application context, for example with the following xml configuration:
<bean class="my.package.MyServiceObject"/>
and inject it to your controller:
private MyServiceObject myServiceObject;
#Autowired
public void setMyServiceObject(MyServiceObject myServiceObject){
this.myServiceObject = myServiceObject;
}
if many instances of MyServiceObject are required, you can declare it as a bean with some other (non-singleton) bean scope (prototype, or request, for example).
However, as there's only one instance of the controller, you can't merely let the Spring container to autowire MyServiceObject instance to the controller field, because there will be only one field and many instances of MyServiceObject class. You can read about the different approaches(for the different bean scopes) for resolving this issue in the respective section of the documentation.
Here is a method that allows us to fetch whatever values are needed from a property file. This can be in Java code (Controller class) or in a JSP.
Create a property file WEB-INF/classes/messageSource.properties It will be in the classpath and accessible in both controllers and JSTL.
Like any property file, this one consists of a key and a value
For example:
hello=Hello JSTL, Hello Contoller
For the Controllers
Locate the xml file that you use to define your Spring beans. In my case it is named servlet-context.xml. You may need to determine that by looking in your web.xml in cases where you are using the servlet contextConfigLocation property.
Add a new Spring bean definition with the id="messageSource". This bean will be loaded at runtime by Spring with the property file key value pairs. Create the bean with the following properties:
bean id="messageSource"
class = org.springframework.context.support.ReloadableResourceBundleMessageSource
property name="basename" value="WEB-INF/classes/messageSource
In the bean definition file for the controller class (testController) add the messageSource as a property. This will inject the messageSource bean into the controller.
bean id="testController" class="com.app.springhr.TestController"
beans:property name="messageSource" ref="messageSource"
In the controller JAVA class, add the messageSource Spring Bean field and its getters and setters. Note the field type is ReloadableResourceBundleMessageSource.
private org.springframework.context.support.ReloadableResourceBundleMessageSource messageSource;
public org.springframework.context.support.ReloadableResourceBundleMessageSource getMessageSource() {
return messageSource;
}
public void setMessageSource(
org.springframework.context.support.ReloadableResourceBundleMessageSource messageSource) {
this.messageSource = messageSource;
}
In your controller code, you can now fetch any known property value from the bundle.
String propValue = getMessageSource().getMessage("hello", objArray, null);
Using JSTL
Since the property file messageSource.properties is in the classpath, JSTL will be able to find it and fetch the value for the given key.
Add the import of the fmt taglib
taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"
Use the fmt:tag in the JSP to fetch a value from the property file.
Sorry about the pseudo syntax, this editor doesn't seem to render any XML.
fmt:bundle basename="messageSource"
fmt:message key="hello"
Hope this helps others

Spring MVC 3.0 with Apache Tiles - Mutiple Forms in one page

I'm using spring mvc (3.0) with apache tiles in my project. I have multiple forms in a single page rendered through tiles.
The login form and search form are common to most pages. The “body” in the tile definition keeps changing.
So, as shown below, in all of my mvc controllers I have to explicitly set command object in the corresponding model.
1. model.put("userBO", userBO);
2. model.put("searchBO", searchBO);
Is there a way I can move this part of the code to a common place or a global controller, so that I don’t have to write these two lines in all the controllers that I write?
You can use an interceptor to do this in a postHandle:
public class DefaultModelInterceptor extends HandlerInterceptorAdapter {
#Override
public void postHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler,
final ModelAndView modelAndView) throws Exception {
modelAndView.addObject("userBO", userBO);
modelAndView.addObject("searchBO", searchBO);
super.postHandle(request, response, handler, modelAndView);
}
}
This can then be wired in your spring servlet config:
<mvc:interceptors>
<bean class="my.package.DefaultModelInterceptor"/>
</mvc:interceptors>

Resources