controller chaing in spring 3 - spring-mvc

i have to call one controller on the basis of first controller i have to call another controller ......
but this is not working in spring 3 mvc........
#Controller
public class ajaxContoller {
#RequestMapping(value="/mmiFacade",method=RequestMethod.POST)
public #ResponseBody String mmiFacade(#RequestParam String sType){
String forwardName = "";
if (sType.equalsIgnoreCase("Pincode")) {
forwardName = "forward:/pincodeAction";
} else if (sType.equalsIgnoreCase("Locality")) {
forwardName = "forward:/localityAction";
} else if (sType.equalsIgnoreCase("Patient")) {
forwardName = "forward:/patientAction";
} else if (sType.equalsIgnoreCase("Dlhdata")) {
forwardName = "forward:/Dlhdata";
}
return forward;
}
#RequestMapping(value="/pincodeAction",method=RequestMethod.POST)
public #ResponseBody String ajax(){
return "hiii";
}
#RequestMapping(value="/localityAction",method=RequestMethod.POST)
public #ResponseBody String ajax1(){
return "hiii1";
}
}

You should return modelandview object. view name starting with "forward:/" will do the job, otherwise Spring does not even try to interpret the response.
Another option to implement a switch and to invoke other mapping as simple call to anther java function.

Returning a String containing the view name does exactly the same thing as returning a ModelAndView object with the view name set to a String. If you just return a String, Spring internally creates a ModelAndView and set the view name to the value of the String.
In your example, you should not annotate the mmiFacade method with #ResponseBody. Using #ResponseBody bypasses the view resolution process, which is where the "forward:" and "redirect:" prefixes in view names are detected and processed.

Related

How to pass a generic collection Class object as an argument

I've RESTful service Spring MVC based.
The service has a RESTful resource method that returns the following response:
public class OperationalDataResponse<T> {
private String status;
private String statusMessage;
private T result;
//getters and setters
}
This response object encapsulates the result object of type T.
On the client side I use RestTemplate with GsonHttpMessageConverter added.
I get the response from service as a ResponseEntity
I handle the generic response with runtime Type as below:
public class OperationalDataRestClient<REQ,RESULT_TYPE> {
public OperationalDataResponse<RESULT_TYPE> getOperationalData(String resourcePath, Map<String, Object> urlVariables, Class<RESULT_TYPE> resultType) {
//code to invoke service and get data goes here
String responseString = responseEntity.getBody();
response = GsonHelper.getInstance().fromJson(responseString, getType(OperationalDataResponse.class, resultType));
}
Type getType(final Class<?> rawClass, final Class<?> parameter) {
return new ParameterizedType() {
#Override
public Type[] getActualTypeArguments() {
return new Type[] { parameter };
}
#Override
public Type getRawType() {
return rawClass;
}
#Override
public Type getOwnerType() {
return null;
}
};
}
}
This works like a charm as long as my resultType is a non-collection class.
So, this works great from caller code:
getOperationalData(someResourcePath, someUrlVariables, MyNonGenericClass.class)
However if my resultType is a collection (say, List<String> or List<MyNonGenericClass>)
then I don't know how to pass the resultType Class from the caller code.
For example, from caller code,
getOperationalData(someResourcePath, someUrlVariables, List.class)
or
getOperationalData(someResourcePath, someUrlVariables, List<MyNonGenericClass>.class)
throws compilation error.
I tried passing on ArrayList.class as well but that too doesn't work.
Any suggestion how can I pass a generic collection as a resultType from caller code (in other words, as an example, how can I pass the class object of a List<String> or List<MyNonGenericClass> from caller code ?)
If you know that ResultType is coming as a List, Then it will obvious fail like you said compilation issue.Why? because you are trying to send a List when you method only accepts a single value.In order to over come that issue you will have to change the method arguments to the following
public OperationalDataResponse<RESULT_TYPE> getOperationalData(String resourcePath, Map<String, Object> urlVariables, List<Class<RESULT_TYPE>> resultType){
....
}
and you will have to make some slight modification to getType() Method,loop it and then pass each class value to getType method like so
for(MyNonGenericClass myClass:mylist){
getType(OperationalDataResponse.class, myClass.getClass());
}

Spring Data, MVC DomainClassConverter how to get to id from request and keep using domain type as param

As part of Spring Data, there is DomainClassConverter which helps with repository lookups so that we don't have to do lookup manually.
http://docs.spring.io/spring-data/commons/docs/current/reference/html/#core.web.basic.domain-class-converter
#Controller
#RequestMapping("/orders/{id}")
public class PaymentController {
#RequestMapping(path = "/payment", method = PUT)
ResponseEntity<?> submitPayment(#PathVariable("id") Order order) {
if (order == null) {
throw new OrderNotFoundException(???orderId???);
}
...
}
}
How can I get to {id} from request without changing Order parameter to Long?
DomainClassConverter converts {id} to null as expected
My intention is to use order id in OrderNotFoundException
I can think of couple of ways.
1. Change the method to
#RequestMapping(path = "/payment", method = PUT)
ResponseEntity<?> submitPayment(#PathVariable("id") Order order, HttpServletRequest request) {
String path = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString()
// path will have "/payment/id". use substring or something similar to get just id
}
Write a #Around Aspect for #RequestMapping and get the argument
#Aspect
#Configuration
public class ControllerAspect {
#Pointcut("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void requestMapping() {}
#Around("requestMapping()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
String path = (String) joinPoint.getArgs()[0];
Object result= joinPoint.proceed();
}
}

Spring MVC #Validation with Marker Interface in Generic Controller Method

I have a Spring MVC survey application where the Controller method called by each form POST is virtually identical:
#PostMapping("/1")
public String processGroupOne (
Model model,
#ModelAttribute("pageNum") int pageNum,
#ModelAttribute(GlobalControllerAdvice.SESSION_ATTRIBUTE_NAME) #Validated(SurveyGroupOne.class) SurveyCommand surveyCommand,
BindingResult result) {
if (result.hasErrors()) {
LOG.debug(result.getAllErrors().toString());
model.addAttribute("pageNum", pageNum);
return "survey/page".concat(Integer.toString(pageNum));
}
pageNum++;
model.addAttribute("pageNum", pageNum);
return "redirect:/survey/".concat(Integer.toString(pageNum));
}
The only difference is what part of the SurveyCommand object is validated at each stop along the way. This is designated by the marker interface passed to the #Validated() annotation. The marker interfaces (SurveyGroupOne, SurveyGroupTwo, etc) are just that, markers:
public interface SurveyGroupOne {}
public interface SurveyGroupTwo {}
...
and they are applied to properties of objects in the SurveyCommand object:
public class Person {
#NotBlank(groups = {
SurveyGroupTwo.class,
SurveyGroupThree.class})
private String firstName;
#NotBlank(groups = {
SurveyGroupTwo.class,
SurveyGroupThree.class})
private String lastName;
...
}
My question: how can I make the method generic and still use the marker interface specific to the page being processed? Something like this:
#PostMapping("/{pageNum}")
public String processGroupOne (
Model model,
#PathVariable("pageNum") int pageNum,
#ModelAttribute(GlobalControllerAdvice.SESSION_ATTRIBUTE_NAME)
#Validated(__what goes here??__) SurveyCommand surveyCommand,
BindingResult result) {
if (result.hasErrors()) {
LOG.debug(result.getAllErrors().toString());
model.addAttribute("pageNum", pageNum);
return "survey/page".concat(Integer.toString(pageNum));
}
pageNum++;
model.addAttribute("pageNum", pageNum);
return "redirect:/survey/".concat(Integer.toString(pageNum));
}
How can I pass the proper marker interface to #Validated based solely on the pageNum #PathVariable (or any other parameter)?
Because #Validated is an annotation, it requires its arguments to be available during compilation and hence static. You can still use it but in this case you will have N methods, where N is a number of steps. To distinguish one step from another you can use params argument of #PostMapping annotation.
There is also another way where you need to inject Validator to the controller and invoke it directly with an appropriate group that you need.

#ExceptionHandler with parameters not working

I am trying to capture all exceptions of some class in my Controller class. It works fine when
I define it like this:
#ExceptionHandler(NoSearchResultException.class)
public String handleNoSearchResultException() {
return "someView";
}
But not if I add any parameters:
#ExceptionHandler(NoSearchResultException.class)
public String handleNoSearchResultException(Exception e) {
return "someView";
}
What could possibly be happening? Also, I've read #ExceptionHandler does not support Model arguments, so how would I pass a parameter (like the error message for instance) to the view in order to offer a dynamic error page?
To pass a parameter to the view I would create a custom Exception class in which you can store any required model parameters (such as error messages). Then in #ExceptionHandler method you can extract those model parameters and make them available in the view. For example:
class RequestException extends RuntimeException {
...
public void setErrorMessages(List<String> errorMsgs) {
this.errorMessages = errorMsgs
}
...
}
#ExceptionHandler(RequestException.class)
public ModelAndView handleNoSearchResultException(RequestException ex) {
ModelAndView mav = new ModelAndView("someView");
mav.addObject("errors", ex.getErrorMessages()); //fetch error messages
return mav;
}
As for parameters, try specifying NoSearchResultException as method parameter instead of it's Exception superclass.
EDIT:
Had a bug in 2nd example return value.
I Solved the problem by passing the custom arguments in request itself.
code is as below :
Controller
#RequestMapping(method = RequestMethod.GET, value = "/exception2")
public String getException1(ModelMap model, #CRequestParam("p") String p, HttpServletRequest request) {
System.out.println("Exception 2 " + p);
request.setAttribute("p", p);
throw new CustomGenericException("1", "2");
}
Exception Handler
#ExceptionHandler(CustomGenericException.class)
public ModelAndView handleCustomException(CustomGenericException ex, HttpServletRequest request) {
ModelAndView model2 = new ModelAndView("error/generic_error");
model2.addObject("exception", ex);
System.out.println(request.getAttribute("p"));
System.out.println("CustomGenericException ");
return model2;
}
here is Sackoverflow question and its answer and
Complete source code is available at git

How to return multiple #ModelAttribute in spring annotated controllers?

I am in the middle of converting my controllers to annotated style controllers in spring mvc.
Basically I do this in the old style controller simpleformcontroller.
protected Map referenceData(HttpServletRequest request) throws Exception
{
Map referenceData = new HashMap();
List<ItemVo> lstItem1 = eqrManager
.searchAllEqptCondQualItems("A1", "BOXES");
List<ItemVo> lstItem2 = eqrManager
.searchAllEqptFullQualItems("A2", "CANNED_GOODS");
referenceData.put("BOX_ITEMS", lstItem1);
referenceData.put("CANNED_ITEMS", lstItem2);
return referenceData;
}
In the annotated, I do something like this:
#ModelAttribute("BOX_ITEMS")
public List<ItemVo> populateCondEQRItems() {
List<ItemVo> lstCondQual = eqrManager
.searchAllEqptCondQualItems("A1", "BOXES");
return lstCondQual;
}
#ModelAttribute("CANNED_ITEMS")
public List<ItemVo> populateFullEQRItems() {
List<ItemVo> lstFullQual = eqrManager
.searchAllEqptFullQualItems("A2", "CANNED_GOODS");
return lstFullQual;
}
My question is, is there a way to return all attributes in just a single method and not
having to create multiple #ModelAttribute? In my case, I need to annotate 2 method? What if I need
3, should I create 3 annotated methods also?
The rule is clear
If you need more than one model attribute, take model as a input argument
#RequestMapping(method=RequestMethod.GET)
public void setUp(Model model) {
model.addAttribute("CANNED_ITEMS", eqrManager.searchAllEqptFullQualItems("A2", "CANNED_GOODS"))
.addAttribute("BOX_ITEMS", eqrManager.searchAllEqptCondQualItems("A1", "BOXES"));
}
Good lucky!
I cannot get it clearly
Ok! I was telling that #ModelAttribute can be put at Method level as well as Method Parameter level. And it behaves differently depends on where you've put it.
#ModelAttribute(user)
public void preRender(Model model) {
/* this method will be invoked before resolving #ModelAttribute Method Parameter i.e. before invoking render/processCreate method */
/* codes are available to CreateUser.jsp if render request comes */
/* codes are available to CreateUser.jsp if validation fails */
model.addAttribute("countryCodes", I18Nservice.getCountryISOCodes());
model.addAttribute("languageCodes", I18Nservice.getLanguageISOCodes());
}
public String renderCreate(#ModelAttribute(value="user") User user) {
return "/user/create";
}
#Override
public String processCreate(#ModelAttribute(value="user") User user, BindingResult result) {
if(result.hasErrors() {
return "/user/create";
}
securityService.createUser(user);
return "/user/detail/user.getId()";
}
If you are new in Spring MVC 3 arena:
read Web MVC framework
Check #RequestMapping JavaDoc
And play with Petcinic & mvc-showcase

Resources