I need to add support for passing field values to a form via a URL parameter when viewing a form which will be used to populate values into the form when it loads. should support a JSON formatted value of field names and values. Example:
https://web/form/view?id=1&data={'fieldname':'value'}
#RequestMapping(value = "/form/view", method = RequestMethod.GET)
public ModelAndView viewDomainForm(HttpSession session, #ModelAttribute("command") FormBean inFormBean) {
Form form = formService.getForm(inFormBean.getId());
FormInstance formInstance = formInstanceService.createFormInstance(form);
String formInstanceId = (String) session.getAttribute("formInstanceId");
if (formInstanceId != null && formInstanceId.length() > 0) {
formInstanceService.deleteFormInstanceById(formInstanceId);
}
formInstanceId = formInstance.getId();
session.setAttribute("formInstanceId", formInstanceId);
FormBean formBean = prepareFormBean(form);
formBean.setEmbed(inFormBean.isEmbed());
formBean.setFormInstanceId(formInstance.getId());
Map<String, Object> model = new HashMap<String, Object>();
model.put("externalBaseUrl", configurationService.getValue("core.external.url.base"));
model.put("fromTaskList", false);
model.put("form", formBean);
model.put("flow", new FlowBean());
model.put("task", new TaskBean());
return new ModelAndView("form-viewer", model);
}
I have this method for viewing. what would be the best way to Populate fields from URL parameter?
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
// this is the value that will populate into the form when it loads.
First question, why not use POST with the JSON in the request body?
If the JSON will be large, then you will run in a URL limitation problem. And you have to encode your URL with % and different delimiters which will make it even less debuggable.
But it is doable.
Let's say that you correctly encoded your URL and the JSON is as a query param.
What you could do is receive it and either traverse it and create/populate your form or map it to an object and use that:
public ModelAndView viewDomainForm(... #RequestParam("data") String jsonDataInUrl...)
{
// Work with jsonDataInUrl either through parsing it or through transforming it into a java bean.
...
}
Here is a URL decoder/encoder in case you need it.
Related
I need to know how Spring boot maps the request parameters in the URL to a POJO at run time.
Here is an example URL with parameters
http://localhost:8080/api/public/properties?serviceType.in=SALE&title.contains=some text&price.greaterOrEqualThan=500&price.lessOrEqualThan=50000&propertyType.in=HOUSE&locationId.in=1,2&landSize.greaterOrEqualThan=100&landSize.lessOrEqualThan=1000&bedrooms.greaterOrEqualThan=2&bedrooms.lessOrEqualThan=5&bathrooms.greaterOrEqualThan=1&bathrooms.lessOrEqualThan=3&ageType.in=BRAND_NEW
I have a number of Criteria classes that all extends PropertyCriteria class. To give an example, if the request contains no parameters, I want the controller to use the PropertyCriteria. If the request contains a bedrooms parameter, I want the controller to use the HousePropertyCriteria and so on. See controller method example below.
#GetMapping("/public/properties")
public ResponseEntity<List<Property>>
getAllPropertiesNested(HttpServletRequest request) {
if (condition1 == true) {
EntityOnePropertyCriteria c1 = new EntityOnePropertyCriteria();
//populate c1 using request object
} else {
EntityTwoPropertyCriteria c2 = new EntityTwoPropertyCriteria();
//populate c2 using request object
}
}
Two ways of doing this manually:
1) I wonder if in your project you have access to HttpServletRequest object. If that is the case, you can use the method request.getParameter(nameParam) to populate the object that you need.
2) Use beanutils library and using the method
BeanUtils.copyProperties(dest, source)
Using "#RequestParam Map source" in your controller and replacing the dest object you want fill
I found the answer on this link.
public static void applyMapOntoInstance(Object instance, Map properties) {
if (properties != null && !properties.isEmpty()) {
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(instance);
beanWrapper.setAutoGrowNestedPaths(true);
for (Iterator<?> iterator = properties.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, ?> entry = (Map.Entry<String, ?>) iterator.next();
String propertyName = entry.getKey();
if (beanWrapper.isWritableProperty(propertyName)) {
beanWrapper.setPropertyValue(propertyName, entry.getValue());
}
}
}
}
My controller method now looks like:
#GetMapping("/public/properties")
#Timed
public ResponseEntity<List<Property>> getAllPropertiesNested(HttpServletRequest request) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
HttpHeaders headers = null;
if (requestContains("bedrooms", request)) {
HousePropertyCriteria housePropertyCriteria = new HousePropertyCriteria();
applyMapOntoInstance(housePropertyCriteria, request.getParameterMap());
Page<HouseProperty> page = housePropertyQueryService.findByCriteriaNested(housePropertyCriteria, pageable);
headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/public/properties");
return new ResponseEntity(page.getContent(), headers, HttpStatus.OK);
} else {
Page<Property> page = propertyQueryService.findByCriteriaNested(criteria, pageable);
headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/public/properties");
return new ResponseEntity(page.getContent(), headers, HttpStatus.OK);
}
}
I have this request
#RequestMapping(value = "/test", method = RequestMethod.POST)
public void test(ModelMap modelMap, #RequestParam(value = "name") String name) {
modelMap.put("result",name);
}
When I call this request from Postman and pass the Name parameter in the request body and in the URL, the result is like this :
But if I remove the parameter from request body, the request is like this :
Why does #RequestParam annotation bind the value from the request body first? and if it doesn't exist in the body, it bind the value from URL parameters
Because it's how ServletRequest works. Behind the scene #RequestParam is using ServletRequest#getParameter. If you take a look at the java doc it clearly state that query parameter or form post data are used.
For HTTP servlets, parameters are contained in the query string or posted form data.
If there is a multiple value for instance same key in query and post data then it returns the first value in the array returned by getParameterValues.
Furthermore you are using multipart/form-data content type so spring handle it with DefaultMultipartHttpServletRequest where parameters found in the body are returned first:
#Override
public String[] getParameterValues(String name) {
String[] parameterValues = super.getParameterValues(name);
String[] mpValues = getMultipartParameters().get(name);
if (mpValues == null) {
return parameterValues;
}
if (parameterValues == null || getQueryString() == null) {
return mpValues;
}
else {
String[] result = new String[mpValues.length + parameterValues.length];
System.arraycopy(mpValues, 0, result, 0, mpValues.length);
System.arraycopy(parameterValues, 0, result, mpValues.length, parameterValues.length);
return result;
}
}
I have to implement a filter to prevent XSS attack in my Liferay Portal. I have read a lot of answers about it, so I used an HttpServletRequestWrapper to add sanitized parameters to my request. My filter works properly: debugging the code I realized that the filter takes the parameter and sanitized it.
My problem is that in the processAction of a portlet I am not able to retrieve the sanitized parameter using request.getParameter() but I always get the old not sanitized parameter.
For example, suppose I have a portlet with a simple form like this:
As you can see in the input field there is a b tag to sanitize. When the form is submitted my filter is invoked and it throws the doFilter() method.
My doFilter method iterates over all parametes doing sanitation. Then I add them in my WrappedRequest:
/*
* Did it make any difference?
*/
if (!Arrays.equals(processedParams, params)) {
logger.info("Parameter: " + params[0] + " sanitized with: " + processedParams[0] );
/*
* If so, wrap up the request with a new version that will return the trimmed version of the param
*/
HashMap<String, String[]> map = new HashMap<>();
map.put(name, processedParams);
final HttpServletRequestWrapper newRequest = new ExtendedRequestWrapper(httpServletRequest,map);
/*
* Return the wrapped request and forward the processing instruction from
* the validation rule
*/
return newRequest;
My class ExtendedRequestWrapper implements getparameter method:
public class ExtendedRequestWrapper extends HttpServletRequestWrapper {
private final Map<String, String[]> modifiableParameters;
private Map<String, String[]> allParameters = null;
public ExtendedRequestWrapper(final HttpServletRequest request,
final Map<String, String[]> additionalParams)
{
super(request);
this.modifiableParameters = new TreeMap<String, String[]>();
this.modifiableParameters.putAll(additionalParams);
}
#Override
public String getParameter(final String name)
{
String[] strings = getParameterMap().get(name);
if (strings != null)
{
return strings[0];
}
return super.getParameter(name);
}
#Override
public Map<String, String[]> getParameterMap()
{
if (this.allParameters == null)
{
this.allParameters = new TreeMap<String, String[]>();
this.allParameters.putAll(super.getParameterMap());
this.allParameters.putAll(modifiableParameters);
}
//Return an unmodifiable collection because we need to uphold the interface contract.
return Collections.unmodifiableMap(allParameters);
}
#Override
public Enumeration<String> getParameterNames()
{
return Collections.enumeration(getParameterMap().keySet());
}
#Override
public String[] getParameterValues(final String name)
{
return getParameterMap().get(name);
}
}
Now, when I try to access to sanitized params in my processAction() I get the old value, that one not sanitized:
#Override
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
String azione = request.getParameter("MyXSSaction");
if(azione.equals("XSSAttack")) {
String descr = req.getParameter("mydescr");
}
}
How can I solve?
You should not do this generically in your input handling. First of all, there is no XSS in <b>, as the second S in XSS is for 'scripting' - and <b> doesn't contain any scripts.
Second, a general and thorough application of such a filter will effectively keep you from adding proper web content, blog articles and other content, where formatting is legitimately done.
Third - let's say you have a random book management system: Why shouldn't people be able to enter Let x < 5 as a book title, or even <script>alert('XSS')</script> and what to do against it - wouldn't they be proper book titles? In fact, they'd be proper data, and you want to escape them when you display.
There might be an argument for sanitizing (like Liferay's AntiSamy plugin does) certain elements if they're meant to be displayed as HTML. But anything else just needs to be properly escaped during output.
Another way to put it: Those parameters are only dangerous if you incorrectly don't escape them when they're shown in HTML pages - but if you embed them in a text/plain email body, they're completely harmless.
I want to return a List of object from a Spring controller to an AJAX request.
AJAX request:
function doAjaxPost(date) {
$.ajax({
type : "POST",
contentType : "application/json",
url : "<%="/water-consumer" + homepageURL + "/hourConsumption"%>",
data : date,
dataType : 'json',
success : function(response) {
if(response != null)
showHourConsumption(response);
}
});
}
Spring controller:
#RequestMapping(value = "/{username}/hourConsumption", method=RequestMethod.POST, produces="application/json")
public #ResponseBody List<HourConsumption> getHoursConsumptions(#RequestBody String day, HttpSession session, Model model) {
// do something ....
Household household = (Household)session.getAttribute("household");
List<HourConsumption> consumptions = this.mrs.getHoursConsumption(household.getSmart_meter().getOid(), day);
// do something
if(consumptions == null) //check if what get back from something is not null
return null;
else
return consumptions;
}
Now, the AJAX request goes right, so I receive the request from the controller and it generates the correct consumptions (List) but when it returns the List, the browser gives me back the following error:
Failed to load resource: the server responded with a status of 406
(Not Acceptable)
Someone could tell me how can I do this things or the correct way to do so?
Thank you very much!
Make sure that following 2 jar's are present in class path.
If any one or both are missing then this error will come.
jackson-core and jackson-mapper
A few pointers:
The http method can be a GET iso a POST.
Remove session and model parameters. If you need session then you can obtain it from an Autowired HttpServletRequest.
Make sure you have Jackson as dependency
The problem is with the data you are returning, to the browser is not well formed JSON. Then I would remove the attribute "produces" from your Controller, and leave the Spring Jackson transformer to create the json entities.
Change your code to this:
#RequestMapping(value = "/{username}/hourConsumption", method=RequestMethod.POST)
public #ResponseBody List<HourConsumption> getHoursConsumptions(#RequestBody String day, HttpSession session, Model model) {
// do something ....
Household household = (Household)session.getAttribute("household");
List<HourConsumption> consumptions = this.mrs.getHoursConsumption(household.getSmart_meter().getOid(), day);
// do something
if(consumptions == null) //check if what get back from something is not null
return null;
else
return consumptions;
}
Try using Google's gson (https://mvnrepository.com/artifact/com.google.code.gson/gson) to send Json format String to the page.
Spring Controller
#RequestMapping(value = "/{username}/hourConsumption", method=RequestMethod.POST)
public #ResponseBody String getHoursConsumptions(#RequestBody String day, HttpSession session, Model model) {
String jsonFormatData = "";
// do something ....
Household household = (Household)session.getAttribute("household");
List<HourConsumption> consumptions = this.mrs.getHoursConsumption(household.getSmart_meter().getOid(), day);
// do something
// **Using Gson**
// You can include this in your bean definition and autowire it
// and use the singleton created by Spring.
// For this example I am instantiating Gson myself
Gson gson = new Gson();
jsonFormatData = gson.toJson(consumptions);
return jsonFormatData;
}
I want setting the attribute in first modelandview method with the help of bean and trying to get the attributes in other modelandview method in same controller but getting null value my code is below
#RequestMapping(value="/insert",method=RequestMethod.POST)
public ModelAndView inserData(#ModelAttribute SavingBeansavingBean,HttpServletRequestrs,Model m) {
System.out.println(savingBean.getFirstName());
if (savingBean != null)
System.out.println("abho");
SavingBean saving = persionalService.insertData(savingBean);
custid = saving.getCustomerId();
System.out.println(custid);
m.addAttribute("customId",saving);
System.out.println(saving.getDisgnProf());
List<SavingBean> list = new ArrayList<SavingBean>();
list.add(saving);
return new ModelAndView("AccountInfo","list", list);
}
#RequestMapping(value="/accinsert",method=RequestMethod.POST)
public ModelAndView inserData(#ModelAttribute AccountBean accbean,HttpServletRequest rs,Model m) {
SavingBean b = new SavingBean();
System.out.println("saas" + b.getCustomerId());
session = rs.getSession();
System.out.println("xxx" + rs.getAttribute("customId"));
accbean.setCustid((Long) rs.getAttribute("customId"));
AccountBean accbean1 = persionalService.insertacc(accbean);
return new ModelAndView("welcome");
}
From the first look to your code , I notice that your request method not specified. At this case (When using #ModelAttribute) you have to make it as (POST) request.
#RequestMapping(value = "/insert", method = RequestMethod.POST)
#RequestMapping(value = "/accinsert" , method = RequestMethod.POST)
Why ? because actually your object will be retrieved due to Form Submission which is treated as POST request. Try that thing and check the results. If the problem is still maybe you have some real problem in your Presentation Layer (e.g JSP Page) that is responsible about submitting the data.
Good Luck !