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
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());
}
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();
}
}
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.
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
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