get param value to generate a chart - servlets

user enter two date
it need to click on a button...
if the date are valid, the same jsp page is called and some value are setted in the request... in this jsp, if setSeachDone is true, a chart is generate...
another servled controller is called for the image... but the value already setted in the request are empty
#Controller
#RequestMapping("/statError")
public class StatisticError {
#Autowired
private IUserService userService;
#InitBinder("statisticForm")
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new StatisticErrorFormValidator());
}
#RequestMapping(method = RequestMethod.GET)
public String statistic(Model model) {
StatisticErrorForm statisticForm = new StatisticErrorForm();
model.addAttribute("statisticForm", statisticForm);
return "statisticError";
}
#RequestMapping(method = RequestMethod.POST)
public String statistiqueResult(#Valid #ModelAttribute StatisticErrorForm statisticForm, BindingResult result, ModelMap model, HttpServletRequest request,
HttpServletResponse response) {
if (!result.hasFieldErrors() && !result.hasErrors()) {
request.setAttribute("startDate", statisticForm.getStartDate());
request.setAttribute("endDate", statisticForm.getEndDate());
statisticForm.setSearchDone(true);
}
model.addAttribute(statisticForm);
return "statisticError";
}
}
the servlet controller
#Controller
#RequestMapping("/statError.jpg")
public class ImageErrorController {
#Autowired
private IUserService userService;
#RequestMapping(method = RequestMethod.GET)
public void generateChart(HttpServletRequest request,
HttpServletResponse response) {
if (request.getAttribute("startDate") != null && request.getAttribute("endDate") != null) {
response.setContentType("image/jpg");
AxisChart axisChart = userService.generateChart();
ServletEncoderHelper.encodeJPEG(axisChart, 1.0f, response);
}
}
is there a way to send the value entered by the user to the imageErrorController?
add the model to generateChart?

You need to pass them as parameters of image URL in your view, like this:
<img src = "<c:url value = "/statError.jpg">
<c:param name = "startDate" value = "${startDate}" />
<c:param name = "endDate" value = "${endDate}" />
</c:url>" />

Related

Add value into request object before validation

I'm using #Restcontroller and #Vaid annotation.
#RequestMapping(path = "/1050"
method = RequestMethod.POST,
headers = {"Content-Type=application/json"},
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
public UserListResp getUserList(#RequestBody #Valid UserListReq request, BindingResult bindingResult,
Principal principal){
UserListResp response = new UserListResp();
if (bindingResult.hasErrors()){
response.setResultCode(102); // Validation error
response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");
} else {
return userService.getUserList(request) ;
}
return response;
}
Incoming request mapped to object which validated.
public class UserListReq {
private String userName;
....
}
I'm not getting this value (userName) from incoming json request, I've got from oAuth service by token.
Is it possible to send userName to validation constraint from #ControllerAdvice ?
#InitBinder
public void dataBinding(WebDataBinder binder, HttpServletRequest req) {
// userName
req.getUserPrincipal().getName();
}
Thanks.
I've found decision
#ControllerAdvice
public class GlobalControllerAdvice {
#InitBinder
public void dataBinding(WebDataBinder binder, HttpServletRequest request) {
binder.bind(new MutablePropertyValues(Collections.singletonMap("userName",request.getUserPrincipal().getName())));
}
}

Why I can't Receive String and It's null

#RequestMapping(value = "/save",method = RequestMethod.POST)
#ResponseStatus(value= HttpStatus.OK)
public void save(String str) throws IOException {
System.out.println(str);
}
all I got is null:
You need to tell Spring where to get str from.
If you're sending the JSON
{ "str": "sasfasfafa" }
You'll need a class that deserialises from this and annotate the method parameter with #RequestBody.
public class StrEntity {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
public class MyController {
#RequestMapping(value = "/save",method = RequestMethod.POST)
#ResponseStatus(value= HttpStatus.OK)
public void save(#RequestBody StrEntity entity) throws IOException {
System.out.println(entity.getStr());
}
}
If you just want to send a string as the request body (i.e. sasfasfafa) instead of the JSON document you can do this:
public class MyController {
#RequestMapping(value = "/save",method = RequestMethod.POST)
#ResponseStatus(value= HttpStatus.OK)
public void save(#RequestBody String str) throws IOException {
System.out.println(str);
}
}
There is no way to send the JSON { "str": "sasfasfafa" } as request body and only have a String as a method parameter in the controller.
Use #RequestParam annotation to get the parameter.
#RequestMapping(value = "/save",method = RequestMethod.POST)
#ResponseStatus(value= HttpStatus.OK)
public void save(#RequestParam(name="str") String str) throws IOException {
System.out.println(str);
}

Possible to modify #ModelAttribute before #Validated is run

Is is possible to modify a #ModelAttribute before it is validated via #Validated.
ie
#RequestMapping(value = "/doSomething", method = RequestMethod.POST)
public final ModelAndView save(
#Validated(value = {myGroup.class}) #ModelAttribute("myObject") MyObject myObject)
I need to change the state of myObject before #Validated is executed
What about add a ModelAttribute populate method?
#ModelAttribute("myObject")
public MyObject modifyBeforeValidate(
#ModelAttribute("myObject") MyObject myObject) {
//modify it here
return myObject;
}
The side affect is this method will be invoked before every #RequestMapping method if I'm not mistaken.
Update1: example
#ModelAttribute("command")
public ChangeOrderCommand fillinUser(
#ModelAttribute("command") ChangeOrderCommand command,
HttpServletRequest request) {
command.setUser(securityGateway.getUserFrom(request));
return command;
}
#RequestMapping(value = "/foo/bar", method = RequestMethod.POST)
public String change(#ModelAttribute("command") ChangeOrderCommand command,
BindingResult bindingResult, Model model, Locale locale) {
}
There are 2 ways to modify the model attribute object before the #Validated will trigger:
Remove #Validated and autowire the validator and manually trigger the validator:
class MyController {
private final Validator validator;
class MyController(Validator validator) {
this.validator = validator;
}
#PostMapping("/doSomething")
public final ModelAndView save(
#ModelAttribute("myObject") MyObject myObject, BindingResult result) {
// edit MyObject here
validator.validate(myObject, result)
// original method body here
}
Decorate the default validator and pre-process the myObject object inside the decorated validator.
class MyController {
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.setValidator(new PreProcessMyObjectValidator(binder.getValidator()));
}
#PostMapping("/doSomething")
public final ModelAndView save(
#Validated(value = {myGroup.class}) #ModelAttribute("myObject") MyObject myObject, BindingResult result) {
...
}
private static class PreProcessMyObjectValidator implements Validator {
private final Validator validator;
public PreProcessMyObjectValidator(Validator validator) {
this.validator = validator;
}
#Override
public boolean supports(#Nonnull Class<?> clazz) {
return validator.supports(clazz);
}
#Override
public void validate(#Nonnull Object target, #Nonnull Errors errors) {
if (target instanceof MyObject) {
MyObject myObject = (MyObject) target;
// manipulate myObject here
}
validator.validate(target, errors);
}
}
}
(This second tip is what I picked up from https://github.com/spring-projects/spring-framework/issues/11103)

How to test POST spring mvc

My problem is to how to call this. I could do
MyObject o = new MyObject();
myController.save(o, "value");
but this is not what I would like to do. I would like the MyObject to be in the request post body? How can this be done?
#Requestmapping(value="/save/{value}", method=RequestMethod.POST)
public void post(#Valid MyObject o, #PathVariable String value{
objectService.save(o);
}
Just to be clear I am talking about unit testing.
Edit:
#RequestMapping(value = "/", method = RequestMethod.POST)
public View postUser(ModelMap data, #Valid Profile profile, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return dummyDataView;
}
data.put(DummyDataView.DATA_TO_SEND, "users/user-1.json");
profileService.save(profile);
return dummyDataView;
}
See sample code below that demonstrates unit testing a controller using junit and spring-test.
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
#Transactional
#ContextConfiguration(locations = {
"classpath:rest.xml"
})
public class ControllerTest{
private MockHttpServletRequest request;
private MockHttpServletResponse response;
#Autowired
private RequestMappingHandlerAdapter handlerAdapter;
#Autowired
private RequestMappingHandlerMapping handlerMapping;
#Before
public void setUp() throws Exception
{
this.request = new MockHttpServletRequest();
request.setContentType("application/json");
this.response = new MockHttpServletResponse();
}
#Test
public void testPost(){
request.setMethod("POST");
request.setRequestURI("/save/test"); //replace test with any value
final ModelAndView mav;
Object handler;
try{
MyObject o = new MyObject();
//set values
//Assuming the controller consumes json
ObjectMapper mapper = new ObjectMapper();
//set o converted as JSON to the request body
//request.setContent(mapper.writeValueAsString(o).getBytes());
request.setAttribute("attribute_name", o); //in case you are trying to set a model attribute.
handler = handlerMapping.getHandler(request).getHandler();
mav = handlerAdapter.handle(request, response, handler);
Assert.assertEquals(200, response.getStatus());
//Assert other conditions.
}
catch (Exception e)
{
}
}
}
You need to use RequestBody:
#Requestmapping(value="/save/{value}", method=RequestMethod.POST)
public void post(#RequestBody MyObject o, #PathVariable String value{
objectService.save(o);
}
general info about request body documentation : http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html#mvc-ann-requestbody

reCaptcha issue with Spring MVC

I've been trying to integrate reCaptcha with my application built on Spring framework, but I am getting this error:
org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'recaptcha_challenge_field' is not present
Could someone help me understand that why am I getting this error. I've got both recaptcha_challenge_field and recaptcha_response_field parameters bound to the User domain object.
Could anybody help me understand what am I missing?
Thanks
Here is the code of the controller I am using, all I am trying to do is register a user with reCaptcha functionality but what I am getting is a http status 400 with the error org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'recaptcha_challenge_field' is not present:
UserManagementController.java
#Controller
public class UserManagementController {
private static final String RECAPTCHA_HTML = "reCaptchaHtml";
#Autowired
private UserService userService;
#Autowired
private ReCaptcha reCaptcha;
#RequestMapping(method=RequestMethod.GET, value="/addNewUser.do")
public ModelAndView addNewUser() {
User user = new User();
String html = reCaptcha.createRecaptchaHtml(null, null);
ModelMap modelMap = new ModelMap();
modelMap.put("user", user);
modelMap.put(RECAPTCHA_HTML, html);
return new ModelAndView("/addNewUser", modelMap);
}
#RequestMapping(method=RequestMethod.POST, value="/addNewUser.do")
public String addNewUser(#Valid User user, BindingResult result,
#RequestParam("recaptcha_challenge_field") String challenge,
#RequestParam("recaptcha_response_field") String response,
HttpServletRequest request,
Model model) {
verifyBinding(result);
String remoteAddr = request.getRemoteAddr();
ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challenge, response);
if (!reCaptchaResponse.isValid()) {
result.rejectValue("captcha", "errors.badCaptcha");
}
model.addAttribute("user", user);
if (result.hasErrors()) {
result.reject("form.problems");
return "addNewUser";
}
return "redirect:showContent.do";
}
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.setAllowedFields(new String[] {
"firstName", "lastName", "email",
"username", "password", "recaptcha_challenge_field", "recaptcha_response_field"
});
}
private void verifyBinding(BindingResult result) {
String[] suppressedFields = result.getSuppressedFields();
if (suppressedFields.length > 0) {
throw new RuntimeException("You've attempted to bind fields that haven't been allowed in initBinder(): "
+ StringUtils.join(suppressedFields, ", "));
}
}
}
Here is the addNewUser.jsp element on the form page for the above controller:
<tr>
<td>Please prove you're a person</td>
<td>${reCaptchaHtml}</td>
<td><form:errors path="captcha" cssStyle="color:red"></form:errors></td>
</tr>
Could you help me understand what am I missing here?
Thanks for reply.
What is the implementation of:
String html = reCaptcha.createRecaptchaHtml(null, null); ?
The reCaptcha html must have the name attribute as "recaptcha_challenge_field"
...
<textarea name="recaptcha_challenge_field" ... />
<input type="hidden" name="recaptcha_response_field" value="manual_challenge" />
...
Captcha is dynamic loaded script on the page. It is better to read captcha parameters from request object as shown in below example:
#RequestMapping(value="/submitCaptcha.web",method = RequestMethod.POST)
public String submitCaptcha(#ModelAttribute("recaptchaBean") RecaptchaBean recaptchaBean,BindingResult result, ModelMap model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String captchaChallenge = request.getParameter("recaptcha_challenge_field");
String captchaText = request.getParameter("recaptcha_response_field"); }

Resources