I have two Spring MVC actions that in this example takes one parameter from a form when submitted:
public ModelAndView login(HttpServletResponse response, HttpServletRequest request,
#RequestParam String requestedURL )
I would like to know if the attribute requestedURL can refer to a declared variable that actually hold the name of the incoming attribute input name="requestURL" ...
class Core {
static String requestedURL = "requestedURL";
}
pseudo code:
public ModelAndView login(..., #RequestParam String #ReadFrom(Core.RequestedURL) )
Notice the #ReadFrom
This is to avoid redundancy. Right now it is called requestedURL but in the future someone might want to change the input parameter name, this shouldn't be a hardcoded string in the applicaton in my opinion.
and
<input name="<%= Core.requestedURL %>" value="<%= requestedURL %>" />
and is read in the method when submitted. But does the attribute name have to be hardcoded in the incoming parameter of the action method?
Thanks!
Yes, it has to be hardcoded as part of the #RequestParam annotation - either hardcoded or refer to a static final variable.
The alternative is to take in a Model/Map as an additional parameter in the method and getting the attribute from that:
public ModelAndView login(HttpServletResponse response, HttpServletRequest request,
Model model ){
String requestedURL = model.asMap().get(Core.requestedURL);
}
Update
You can refer to a static final variable this way:
assuming:
public abstract class Core {
public static final String requestedURL = "requestedURL";
}
public ModelAndView login(..., #RequestParam(Core.requestedURL) String requestedURL)
Related
I am new with Spring mvc. I need to pass an javascript variable to controller. How to achieve this??
Form tag solution is not appropriate in case of my application.
I need to pass this start variable of JS to my controller.In some cases this variable can be null or not available as per requirements.
Please suggest asap!!!
My JS code is:
function clickPaginate(start){
var X = '<%=url%>';
window.location.href=X+'/library/${publisher}';
}
and controller is:
#RequestMapping(value = "/library/{publisher}", method = RequestMethod.GET)
public String getPublisherDetails(#PathVariable("publisher") String publisher, ModelMap model) throws FeedsException {
}
There is an annotation #RequestParam that you'll have to use in the method. In your case
window.location.href=X+'/library/${publisher}?foo=bar';
foo is the request parameter with value bar that you are passing to your method.
Your method should be like
public String getPublisherDetails(#RequestParam("foo") String foo, #PathVariable("publisher") String publisher, ModelMap model)
Check out this mvc doc
for example, I have an add method, which in "get" show a form
and in "post" do the add logic, that is validate, call service method and etc.
in the "get" phase, I don't want validate
but the struts2 always validate in those two phase.
How can I config struts2 to only validate on "post" ?
Forget about the REST behavior call the same URL and do different things basing on the Http verbs you are used to:
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public ModelAndView ReadFoobar(Locale locale,
Model model,
HttpServletRequest request){
String foobar = getService().loadFoobar();
ModelAndView mav = new ModelAndView("foobarPage")
mav.addObject("foobar",foobar);
return mav;
}
#RequestMapping(value = "/foo", method = RequestMethod.POST)
public String InsertStuff(#RequestParam("stuff") String stuff,
Locale loc,
Model model,
HttpServletRequest req){
validate();
getService().insertStuff(stuff);
return "stuffPage";
}
That is Spring MVC, this is Struts2. You need to reason in terms of Actions; instead of working with Http verbs, use different Actions and define the validation for only one of them. For example:
Action representing GET
public class ReadFoobar {
#Getter private String foobar;
public String execute(){
foobar = getService().loadFoobar();
return SUCCESS;
}
}
Action representing POST
public class InsertStuff {
#Setter private String stuff = "";
public String execute(){
getService().insertStuff(stuff);
return SUCCESS;
}
public void validate(){
if (stuff.length()<3){
addFieldError("stuff","The mininum length is 3");
}
}
}
At this point, associate your readAction only to GET requests:
<s:a action="ReadFoobar">check out this Foobar</s:a>
and insertAction only to POST requests:
<s:form action="InsertStuff" theme="simple">
<s:textfield name="stuff" />
<s:fielderror fieldName="stuff" />
<s:submit value="Insert the stuff" />
</s:form>
You can do the same with XML Validation by specifying a different XML file for each Action class; You can also have two methods in the same Action class, and specify different XML validation (or no validation) at method level, by renaming the XML with the method name after the action name.
Finally, if you still want to be SURE that absolutely no requests, even when cratfed to bypass your UI, can reach eg. ReadFoobar in GET mode, you can write a simple Interceptor (or two if you don't want to pass GET / POST as parameter) and apply it to the desired Action(s).
Eg. write a BlockGetRequestsInterceptor that will block all the GET requests, and apply it to InsertStuff Action (either by struts.xml or with annotations, if using the Convention plugin, that I recommend):
public class InsertStuff {
#Action(interceptorRefs={
#InterceptorRef("BlockGetRequestsInterceptor"),
#InterceptorRef("defaultStack")})
public String execute(){
getService().insertStuff(stuff);
return SUCCESS;
}
// ...
I like Spring MVC too, but IF you want / need / are using Struts2, use it the right way, the way it is designed for, otherwise it could turn into a nightmare ;)
Given a Spring-MVC controller method:
#RequestMapping(value = "/method")
public void method(#RequestParam int param1,
#RequestParam int param2) { /*...*/ }
If parameters are missing in the request URL, an error is reported, e.g:
JBWEB000068: message Required int parameter 'param1' is not present
I need to move the parameters into a single model class yet keep exactly the same GET request URL. So have modified method's parameter to MyModel model, which contains param1 and param2.
This works if #RequestParam is omitted but the snag is no error is reported if parameters are missing. If, on the other hand #RequestParam is included, a parameter named "model" is expected in the GET request. Is there a way to make model parameters mandatory yet keep the same request URL?
Use JSR-303 annotations to validate the object (and don't use primitives but the Object representations in that case).
public class MyObject {
#NotNull
private Integer param1;
#NotNull
private Integer param2;
// Getters / Setters
}
Controller method.
#RequestMapping(value = "/method")
public void method(#Valid MyObject obj) { /*...*/ }
If you don't have a JSR-303 provider (hibernate-validator for instance) on your classpath create a Validator and use this to validate your object.
Links.
Spring MVC reference guide
Spring Validation reference guide
You can try #ModelAttribute and method=RequestMethod.POST:
In your controller:
//...
#RequestMapping(value="/method", method=RequestMethod.POST)
public String add(#ModelAttribute("modelName") ModelClass form)
{
//.. your code
}
//..
In your JSP:
<%# taglib uri="http://www.springframework.org/tags/form" prefix="f" %>
//.. some code
<f:form action="method" method="post" modelAttribute="modelName">
</f:form>
If you are restricted to GET requests only, you might not be able to use a separate ModelClass. You need to resort to request parameters in that case.
On Java MVC Controller how to get the value of annotation #RequestMapping("/getThisValueFromOtherClass")? I know we can extract this by using java reflections but is there any other way? Thank you.
#RequestMapping("/getThisString")
public class MyController{}
If the purpose is just to avoid changing the url at every place, I will suggest define a string constant in some class and instead of using hard coded string in request mapping use that constant every where.
In future if u want tp\o change the url, simple update the constant value at one place
final String constUrl = "/myurl";
#RequestMapping(value=constUrl)
you can make the constant static, if defining in another class
The value of the annotation can be read programmatically:
#RequestMapping("/endpoints")
public ResponseEntity<String> getPath() {
String path = getClass().getAnnotation(RequestMapping.class).value()[0];
return new ResponseEntity<String>(path, HttpStatus.OK);
}
To obtain the path, you should pass the Request i.e. HttpServletRequest as a parameter to your handler method.
#RequestMapping(value={"/getThisString"}, method=RequestMethod.GET)
public String handlerMethod (Model model, HttpServletRequest request) throws Exception {
String getThatString = request.getServletPath();
....
}
Reference:
HttpServletRequest
In your case if an URI pattern “/getThisString” is requested, it will map to this MyController, and handle the request with method where #RequestMapping(method = RequestMethod.GET) is declared.
You can refer this tutorial #RequestMapping example
Hope it helps.
I have a <TITLE> tag in my JSPs that is set using a value from the request handler:
<title><c:out value="${title}"/></title>
I created a method to do this to try to avoid adding mess to the Controller logic with this extra information.
But I'm still not happy with the way this looks in the code (My actual controller methods are much longer than the examples provided here so I'm trying to minimize and simplify them as much as possible).
Is there a more consise way of adding this information from within the Controller? (It can't be added in the JSPs).
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public final String foo(final ModelMap model) {
addTitle(model, "Desolation Row is the title of this page");
return "foo";
}
#RequestMapping(value = "/goo", method = RequestMethod.GET)
public final String goo(final ModelMap model) {
addTitle(model, "Leopardskin Pillbox Hat is the title of this page");
return "goo";
}
public ModelMap addTitle(ModelMap model, String title) {
model.addAttribute("title", title);
return model;
}
If you want to factor out the addTitle method from your controllers, maybe you can put them in a HandlerInterceptor implementation?
Something like this maybe:
public class TitleInterceptor implements HandlerInterceptor {
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
String requestUrl = (String)request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String title = "";
if ("/url1.htm".equals(requestUrl)) {
title = "Title 1";
} else if ("/url2.htm".equals(requestUrl)) {
title = "Title 2";
}
modelAndView.getModel().put("title", title)
}
}
If you need some processing to determine the title, maybe the modelAndView available to the interceptor will contain the data that will help in determining the title given the url. If no processing is needed, just a simple mapping of a title to a url, you can even implement it as configurable Map during bean configuration in your applicationContext.xml
Some links I found helpful in implementing HandlerInterceptor can be found here:
http://whitesboard.blogspot.com/2009/10/handlerinterceptors-in-spring-web-mvc.html
http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/web/servlet/HandlerInterceptor.html
If you don't want to go down the Interceptor or Aspect road (keeping everything in the Controller):
Create a BaseController that all Controllers extend
Have a HashMap in the BaseController mapping URLs to Titles
Put the addTitle method there too, modifying to return the same string as the JSP name.
BaseController code:
public ModelMap addTitle(ModelMap model, String page) {
model.addAttribute("title", titleMap.get(page));
return page;
}
Controller code becomes:
#RequestMapping(value = "/goo", method = RequestMethod.GET)
public final String goo(final ModelMap model) {
return super.addTitle(model, "goo");
}