Spring MVC annotations always requires Response object - java

I am trying to convert controllers from the old inheritance framework to the new annotations.
Here's an existing controller:
public class SelectedTabController extends AbstractController {
private TabSelectionHelper tabSelectionHelper;
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
String param = request.getParameter("selectedTab");
if (param != null)
tabSelectionHelper.setSelectedTabTo(param);
return null;
}
public void setTabSelectionHelper(TabSelectionHelper tabSelectionHelper) {
this.tabSelectionHelper = tabSelectionHelper;
}
And after conversion I have this:
#Controller
public class SelectedTabController {
private TabSelectionHelper tabSelectionHelper;
#Autowired
public SelectedTabController(#Qualifier(value = "tabSelectionHelper") TabSelectionHelper tabSelectionHelper) {
this.tabSelectionHelper = tabSelectionHelper;
}
#RequestMapping("/selectedTab")
public void selectTab(String selectedTab, HttpServletResponse response) throws Exception {
//String param = request.getParameter("selectedTab");
if (selectedTab != null)
tabSelectionHelper.setSelectedTabTo(selectedTab);
}
}
This works but there is a (redundant) HttpServletResponse object in the selectTab paramter list. If I remove it, then the JQuery call says the server returns 500 and the call fails.
Any help?
The stacktrace shows:
javax.servlet.ServletException: Could not resolve view with name 'selectedTab' in servlet with name 'prodman'
So it is trying to find a view and failing. However, there is NO view to display as its a backend callby JQuery.
I guess by declaring the response object, Spring thinks I will write the response.
How can I prevent Spring from trying to resolve a view?

When you use void as your return type Spring will by default try to determine the view name from your method name, unless it thinks you're directly writing the response (which it does when you have a HttpServletResponse as a parameter). Have a look at section 15.3.2.3 of the Spring 3 docs.
You might want to try changing the return type to ModelAndView and return null and see what happens (I'm not certain you can get away with a null view with #RequestMapping as it's not something that I have ever tried)

Related

Spring MVC: IP restriction for a single controller method

I need to hide a specific API for requests coming form IP different to a specific one.
For instance this should work if I try to use it and my IP is 192.168.1.1, but not if my IP is 192.168.1.2.
#RequestMapping(value = "/test/{id}", method = RequestMethod.GET)
#ResponseBody
#IpRestricted
public void download(#PathVariable("id") String id) {
...
}
I read I can make it creating a specific annotation, the one I called "#IpRestricted" in this example, but than how can I proceed? There are better solution to this?
I then realized I can make it without using spring security.
I made an annotation like this:
#Retention(RetentionPolicy.RUNTIME)
public #interface IpRestricted {
}
Than I check the request IP address inside a HandlerInterceptor preHandle method:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod)handler;
if (method.getMethodAnnotation(IpRestricted.class)!=null) {
if (!request.getRemoteAddr().equals("192.168.1.1")) {
throw new UnauthorizedException("Ip not authorized");
}
}
}
[....]
}
And for the download method:
#RequestMapping(value = "/test/{id}", method = RequestMethod.GET)
#ResponseBody
#IpRestricted
public void download(#PathVariable("id") String id) {
...
}
That's it!
I think the best Spring solution available for this case is the hasIpAddress() method from Spring Security. There are many different ways to configure permissions to your services via Spring Security, and the IP-based solution is also implemented.
Here is a good example of how to set it up.

Significance of return type in spring file download controllers

What is the significance of return type in spring controllers which are used for download. Please consider the following use case:
public ModelAndView execute(final HttpServletRequest request, final HttpServletResponse response) {
try {
//some code.
} catch {
//handle the exception and build a error model and view. This model and view
//gives a lot of freedom for error handling in case of download fails on the
//same page without change in URL(enabling refresh of the same page again
//and again)
return modelAndView;
}
return null;
}
but generally I have seen controllers which has void return types which would look like the one below
public void execute(final HttpServletRequest request, final HttpServletResponse response) {
try {
//some code.
} catch {
//handle the exception but you cannot display the error with out leaving the same page. Error embedding is not possible without changing the URL.
}
}
I have two question here:
a) Are their any disadvantages of one approach over other. I see first serves more use cases than second.
b)Is there any disadvantage of returning null instead of ModelAndView.
References:
Downloading a file from spring controllers
Error handling by redirection in spring download file controller
Nothing bad as for marking method as void. You are handling download action via HttpServletResponse.
There are suggestions that FileSystemResource is cleaner but take into account that for e.g. there are cases that you need to forward your data to some other place in order to compose the report in the other place.
Also Spring lets you easily handle exceptions even when your return type in the controller is void:
#RequestMapping(value = "/pdf-report/{id}.pdf", method = RequestMethod.GET)
public void downloadPdfReport(#PathVariable String id, HttpServletRequest req, HttpServletResponse resp) throws Exception {
//supposed logic here
//if we are failing here then
throw new UserFriendlyException("Cannot produce data");
}
Then ControllerAdvice plays its role:
#ControllerAdvice
public class ExceptionControllerAdvice {
#ExceptionHandler(UserFriendlyException.class)
public ModelAndView handleUserFriendlyException(UserFriendlyException ex) {
//handle here your custom error page
}
}
More info on that from the Spring resources

How to read request parameter values Using HandlerInterceptor in spring?

I'm using HandlerInterceptor to trigger all the events/actions happens in my applications and save it to audit table. In table I'm saving the information like servername, session, parameters etc..
So using HandlerInterceptor how can I read all those parameters values and the pathvariable values what I'm passing in my controller.
Here is my code :
public class AuditInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
LOG.debug("URL path"+request.getRequestURI());
return true;
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
LOG.debug("URL PATH :"+request.getRequestURI());
}
}
My controller class enter code here::
public class ABCDController {
#RequestMapping(value="categories",method=RequestMethod.GET)
#ResponseBody
public List<Category> getCategoryList(#RequestParam String divisions){
return service.getCategoryList(divisions);
}
}
So how can I read the parameter name and values using HandlerInterceptor's HttpServletRequest request object.
The Servlet API provides a way to read the Request Parameters. For example,
ServletRequest.getParameterMap() returns a map of key-values of the request parameters.
However, for Path variables and values, I don't know if Spring MVC offers a simplified way of doing it, but using Servlet API again, you can read the URI using HttpServletRequest.getRequestURI(). You'll have to have your own logic to split it up into appropriate Path parameters.
You should be able to get the variables and its values as a map using the following,
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
final Map<String, String> variableValueMap = (Map<String, String>) request
.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
variableValueMap.forEach((k,v)->System.out.println("Key:"+k+"->"+"Value : "+v));
return true;
}

how to get data from spring controller without annotation

i am using Spring 3.x for my MVC application without annotation. I want to get data only not view . I google it and found it is possible using #ResponseBody . but i dont want to use annotation. how can i tell spring it is only data not a view without annotation. my sample code given below .
public class ShowGraphController extends AbstractController {
private JdbcUserDao userDao;
public void setUserDao(JdbcUserDao userDao) {
this.userDao = userDao;
}
protected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse responce) throws Exception {{
return new ModelAndView("want it retun as a data not a view name only");
}
}
I assume you mean JSON when you say data?
If you have to use ModelAndView style just handle the HttpServletResponse yourself and return null.
It is bit convoluted as with Spring 3, you should ideally be using ResponseBody annotation. Have a look at this class ResponseEntity , this may be useful for your purpose. Sample code from Spring doc :
#RequestMapping("/handle")
public ResponseEntity<String> handle() {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new
ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}
the easiest way is to use #ResponseBody, but if you do not want to use Annotation, you can populate response yourself:
protected void handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {
response.getWriter().println("want it retun as a data not a view name only");
}

ExceptionHandling with Spring 3

I have this controller:
#RequestMapping(value = "*.xls", method = RequestMethod.GET)
public String excel(Model model) {
return "excel";
The excel wiew opens actually a ExcelViewer, which is build in method
protected void buildExcelDocument(Map<String, Object> map, WritableWorkbook ww, HttpServletRequest hsr, HttpServletResponse hsr1) throws Exception {
Class.writecontent
Class.writeMoreContent
Called methods write content to the Excel sheet and they can throw e.g biffException. How can I show a certain error page when Exception is occured?
I tried this
#Controller
public class ExcelController
{
#ExceptionHandler(BiffException.class)
public String handleException(BiffException ex) {
return "fail";
}
#RequestMapping(value = "*.xls", method = RequestMethod.GET)
public String excel(Model model) {
return "excel";
}
}
But I'm getting the server's error message about Exceptions. Maybe a bean definition missing?
#ExceptionHandler-annotated methods only handle exceptions thrown by handler methods in the same class. Your exception, on the other hand, is being thrown from within the View's render method, at which point it's left the controller/handler layer.
Handling exceptions from within the view layer isn't well handled in Spring, mainly because it's hard to get it to work reliably with the servlet API, so I recommend you create a subclass of ExcelView and handle the exception in there.

Categories