001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.bind; 018 019import javax.servlet.ServletRequest; 020 021import org.springframework.lang.Nullable; 022 023/** 024 * Parameter extraction methods, for an approach distinct from data binding, 025 * in which parameters of specific types are required. 026 * 027 * <p>This approach is very useful for simple submissions, where binding 028 * request parameters to a command object would be overkill. 029 * 030 * @author Juergen Hoeller 031 * @author Keith Donald 032 * @since 2.0 033 */ 034public abstract class ServletRequestUtils { 035 036 private static final IntParser INT_PARSER = new IntParser(); 037 038 private static final LongParser LONG_PARSER = new LongParser(); 039 040 private static final FloatParser FLOAT_PARSER = new FloatParser(); 041 042 private static final DoubleParser DOUBLE_PARSER = new DoubleParser(); 043 044 private static final BooleanParser BOOLEAN_PARSER = new BooleanParser(); 045 046 private static final StringParser STRING_PARSER = new StringParser(); 047 048 049 /** 050 * Get an Integer parameter, or {@code null} if not present. 051 * Throws an exception if it the parameter value isn't a number. 052 * @param request current HTTP request 053 * @param name the name of the parameter 054 * @return the Integer value, or {@code null} if not present 055 * @throws ServletRequestBindingException a subclass of ServletException, 056 * so it doesn't need to be caught 057 */ 058 @Nullable 059 public static Integer getIntParameter(ServletRequest request, String name) 060 throws ServletRequestBindingException { 061 062 if (request.getParameter(name) == null) { 063 return null; 064 } 065 return getRequiredIntParameter(request, name); 066 } 067 068 /** 069 * Get an int parameter, with a fallback value. Never throws an exception. 070 * Can pass a distinguished value as default to enable checks of whether it was supplied. 071 * @param request current HTTP request 072 * @param name the name of the parameter 073 * @param defaultVal the default value to use as fallback 074 */ 075 public static int getIntParameter(ServletRequest request, String name, int defaultVal) { 076 if (request.getParameter(name) == null) { 077 return defaultVal; 078 } 079 try { 080 return getRequiredIntParameter(request, name); 081 } 082 catch (ServletRequestBindingException ex) { 083 return defaultVal; 084 } 085 } 086 087 /** 088 * Get an array of int parameters, return an empty array if not found. 089 * @param request current HTTP request 090 * @param name the name of the parameter with multiple possible values 091 */ 092 public static int[] getIntParameters(ServletRequest request, String name) { 093 try { 094 return getRequiredIntParameters(request, name); 095 } 096 catch (ServletRequestBindingException ex) { 097 return new int[0]; 098 } 099 } 100 101 /** 102 * Get an int parameter, throwing an exception if it isn't found or isn't a number. 103 * @param request current HTTP request 104 * @param name the name of the parameter 105 * @throws ServletRequestBindingException a subclass of ServletException, 106 * so it doesn't need to be caught 107 */ 108 public static int getRequiredIntParameter(ServletRequest request, String name) 109 throws ServletRequestBindingException { 110 111 return INT_PARSER.parseInt(name, request.getParameter(name)); 112 } 113 114 /** 115 * Get an array of int parameters, throwing an exception if not found or one is not a number.. 116 * @param request current HTTP request 117 * @param name the name of the parameter with multiple possible values 118 * @throws ServletRequestBindingException a subclass of ServletException, 119 * so it doesn't need to be caught 120 */ 121 public static int[] getRequiredIntParameters(ServletRequest request, String name) 122 throws ServletRequestBindingException { 123 124 return INT_PARSER.parseInts(name, request.getParameterValues(name)); 125 } 126 127 128 /** 129 * Get a Long parameter, or {@code null} if not present. 130 * Throws an exception if it the parameter value isn't a number. 131 * @param request current HTTP request 132 * @param name the name of the parameter 133 * @return the Long value, or {@code null} if not present 134 * @throws ServletRequestBindingException a subclass of ServletException, 135 * so it doesn't need to be caught 136 */ 137 @Nullable 138 public static Long getLongParameter(ServletRequest request, String name) 139 throws ServletRequestBindingException { 140 141 if (request.getParameter(name) == null) { 142 return null; 143 } 144 return getRequiredLongParameter(request, name); 145 } 146 147 /** 148 * Get a long parameter, with a fallback value. Never throws an exception. 149 * Can pass a distinguished value as default to enable checks of whether it was supplied. 150 * @param request current HTTP request 151 * @param name the name of the parameter 152 * @param defaultVal the default value to use as fallback 153 */ 154 public static long getLongParameter(ServletRequest request, String name, long defaultVal) { 155 if (request.getParameter(name) == null) { 156 return defaultVal; 157 } 158 try { 159 return getRequiredLongParameter(request, name); 160 } 161 catch (ServletRequestBindingException ex) { 162 return defaultVal; 163 } 164 } 165 166 /** 167 * Get an array of long parameters, return an empty array if not found. 168 * @param request current HTTP request 169 * @param name the name of the parameter with multiple possible values 170 */ 171 public static long[] getLongParameters(ServletRequest request, String name) { 172 try { 173 return getRequiredLongParameters(request, name); 174 } 175 catch (ServletRequestBindingException ex) { 176 return new long[0]; 177 } 178 } 179 180 /** 181 * Get a long parameter, throwing an exception if it isn't found or isn't a number. 182 * @param request current HTTP request 183 * @param name the name of the parameter 184 * @throws ServletRequestBindingException a subclass of ServletException, 185 * so it doesn't need to be caught 186 */ 187 public static long getRequiredLongParameter(ServletRequest request, String name) 188 throws ServletRequestBindingException { 189 190 return LONG_PARSER.parseLong(name, request.getParameter(name)); 191 } 192 193 /** 194 * Get an array of long parameters, throwing an exception if not found or one is not a number. 195 * @param request current HTTP request 196 * @param name the name of the parameter with multiple possible values 197 * @throws ServletRequestBindingException a subclass of ServletException, 198 * so it doesn't need to be caught 199 */ 200 public static long[] getRequiredLongParameters(ServletRequest request, String name) 201 throws ServletRequestBindingException { 202 203 return LONG_PARSER.parseLongs(name, request.getParameterValues(name)); 204 } 205 206 207 /** 208 * Get a Float parameter, or {@code null} if not present. 209 * Throws an exception if it the parameter value isn't a number. 210 * @param request current HTTP request 211 * @param name the name of the parameter 212 * @return the Float value, or {@code null} if not present 213 * @throws ServletRequestBindingException a subclass of ServletException, 214 * so it doesn't need to be caught 215 */ 216 @Nullable 217 public static Float getFloatParameter(ServletRequest request, String name) 218 throws ServletRequestBindingException { 219 220 if (request.getParameter(name) == null) { 221 return null; 222 } 223 return getRequiredFloatParameter(request, name); 224 } 225 226 /** 227 * Get a float parameter, with a fallback value. Never throws an exception. 228 * Can pass a distinguished value as default to enable checks of whether it was supplied. 229 * @param request current HTTP request 230 * @param name the name of the parameter 231 * @param defaultVal the default value to use as fallback 232 */ 233 public static float getFloatParameter(ServletRequest request, String name, float defaultVal) { 234 if (request.getParameter(name) == null) { 235 return defaultVal; 236 } 237 try { 238 return getRequiredFloatParameter(request, name); 239 } 240 catch (ServletRequestBindingException ex) { 241 return defaultVal; 242 } 243 } 244 245 /** 246 * Get an array of float parameters, return an empty array if not found. 247 * @param request current HTTP request 248 * @param name the name of the parameter with multiple possible values 249 */ 250 public static float[] getFloatParameters(ServletRequest request, String name) { 251 try { 252 return getRequiredFloatParameters(request, name); 253 } 254 catch (ServletRequestBindingException ex) { 255 return new float[0]; 256 } 257 } 258 259 /** 260 * Get a float parameter, throwing an exception if it isn't found or isn't a number. 261 * @param request current HTTP request 262 * @param name the name of the parameter 263 * @throws ServletRequestBindingException a subclass of ServletException, 264 * so it doesn't need to be caught 265 */ 266 public static float getRequiredFloatParameter(ServletRequest request, String name) 267 throws ServletRequestBindingException { 268 269 return FLOAT_PARSER.parseFloat(name, request.getParameter(name)); 270 } 271 272 /** 273 * Get an array of float parameters, throwing an exception if not found or one is not a number. 274 * @param request current HTTP request 275 * @param name the name of the parameter with multiple possible values 276 * @throws ServletRequestBindingException a subclass of ServletException, 277 * so it doesn't need to be caught 278 */ 279 public static float[] getRequiredFloatParameters(ServletRequest request, String name) 280 throws ServletRequestBindingException { 281 282 return FLOAT_PARSER.parseFloats(name, request.getParameterValues(name)); 283 } 284 285 286 /** 287 * Get a Double parameter, or {@code null} if not present. 288 * Throws an exception if it the parameter value isn't a number. 289 * @param request current HTTP request 290 * @param name the name of the parameter 291 * @return the Double value, or {@code null} if not present 292 * @throws ServletRequestBindingException a subclass of ServletException, 293 * so it doesn't need to be caught 294 */ 295 @Nullable 296 public static Double getDoubleParameter(ServletRequest request, String name) 297 throws ServletRequestBindingException { 298 299 if (request.getParameter(name) == null) { 300 return null; 301 } 302 return getRequiredDoubleParameter(request, name); 303 } 304 305 /** 306 * Get a double parameter, with a fallback value. Never throws an exception. 307 * Can pass a distinguished value as default to enable checks of whether it was supplied. 308 * @param request current HTTP request 309 * @param name the name of the parameter 310 * @param defaultVal the default value to use as fallback 311 */ 312 public static double getDoubleParameter(ServletRequest request, String name, double defaultVal) { 313 if (request.getParameter(name) == null) { 314 return defaultVal; 315 } 316 try { 317 return getRequiredDoubleParameter(request, name); 318 } 319 catch (ServletRequestBindingException ex) { 320 return defaultVal; 321 } 322 } 323 324 /** 325 * Get an array of double parameters, return an empty array if not found. 326 * @param request current HTTP request 327 * @param name the name of the parameter with multiple possible values 328 */ 329 public static double[] getDoubleParameters(ServletRequest request, String name) { 330 try { 331 return getRequiredDoubleParameters(request, name); 332 } 333 catch (ServletRequestBindingException ex) { 334 return new double[0]; 335 } 336 } 337 338 /** 339 * Get a double parameter, throwing an exception if it isn't found or isn't a number. 340 * @param request current HTTP request 341 * @param name the name of the parameter 342 * @throws ServletRequestBindingException a subclass of ServletException, 343 * so it doesn't need to be caught 344 */ 345 public static double getRequiredDoubleParameter(ServletRequest request, String name) 346 throws ServletRequestBindingException { 347 348 return DOUBLE_PARSER.parseDouble(name, request.getParameter(name)); 349 } 350 351 /** 352 * Get an array of double parameters, throwing an exception if not found or one is not a number. 353 * @param request current HTTP request 354 * @param name the name of the parameter with multiple possible values 355 * @throws ServletRequestBindingException a subclass of ServletException, 356 * so it doesn't need to be caught 357 */ 358 public static double[] getRequiredDoubleParameters(ServletRequest request, String name) 359 throws ServletRequestBindingException { 360 361 return DOUBLE_PARSER.parseDoubles(name, request.getParameterValues(name)); 362 } 363 364 365 /** 366 * Get a Boolean parameter, or {@code null} if not present. 367 * Throws an exception if it the parameter value isn't a boolean. 368 * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true; 369 * treats every other non-empty value as false (i.e. parses leniently). 370 * @param request current HTTP request 371 * @param name the name of the parameter 372 * @return the Boolean value, or {@code null} if not present 373 * @throws ServletRequestBindingException a subclass of ServletException, 374 * so it doesn't need to be caught 375 */ 376 @Nullable 377 public static Boolean getBooleanParameter(ServletRequest request, String name) 378 throws ServletRequestBindingException { 379 380 if (request.getParameter(name) == null) { 381 return null; 382 } 383 return (getRequiredBooleanParameter(request, name)); 384 } 385 386 /** 387 * Get a boolean parameter, with a fallback value. Never throws an exception. 388 * Can pass a distinguished value as default to enable checks of whether it was supplied. 389 * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true; 390 * treats every other non-empty value as false (i.e. parses leniently). 391 * @param request current HTTP request 392 * @param name the name of the parameter 393 * @param defaultVal the default value to use as fallback 394 */ 395 public static boolean getBooleanParameter(ServletRequest request, String name, boolean defaultVal) { 396 if (request.getParameter(name) == null) { 397 return defaultVal; 398 } 399 try { 400 return getRequiredBooleanParameter(request, name); 401 } 402 catch (ServletRequestBindingException ex) { 403 return defaultVal; 404 } 405 } 406 407 /** 408 * Get an array of boolean parameters, return an empty array if not found. 409 * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true; 410 * treats every other non-empty value as false (i.e. parses leniently). 411 * @param request current HTTP request 412 * @param name the name of the parameter with multiple possible values 413 */ 414 public static boolean[] getBooleanParameters(ServletRequest request, String name) { 415 try { 416 return getRequiredBooleanParameters(request, name); 417 } 418 catch (ServletRequestBindingException ex) { 419 return new boolean[0]; 420 } 421 } 422 423 /** 424 * Get a boolean parameter, throwing an exception if it isn't found 425 * or isn't a boolean. 426 * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true; 427 * treats every other non-empty value as false (i.e. parses leniently). 428 * @param request current HTTP request 429 * @param name the name of the parameter 430 * @throws ServletRequestBindingException a subclass of ServletException, 431 * so it doesn't need to be caught 432 */ 433 public static boolean getRequiredBooleanParameter(ServletRequest request, String name) 434 throws ServletRequestBindingException { 435 436 return BOOLEAN_PARSER.parseBoolean(name, request.getParameter(name)); 437 } 438 439 /** 440 * Get an array of boolean parameters, throwing an exception if not found 441 * or one isn't a boolean. 442 * <p>Accepts "true", "on", "yes" (any case) and "1" as values for true; 443 * treats every other non-empty value as false (i.e. parses leniently). 444 * @param request current HTTP request 445 * @param name the name of the parameter 446 * @throws ServletRequestBindingException a subclass of ServletException, 447 * so it doesn't need to be caught 448 */ 449 public static boolean[] getRequiredBooleanParameters(ServletRequest request, String name) 450 throws ServletRequestBindingException { 451 452 return BOOLEAN_PARSER.parseBooleans(name, request.getParameterValues(name)); 453 } 454 455 456 /** 457 * Get a String parameter, or {@code null} if not present. 458 * @param request current HTTP request 459 * @param name the name of the parameter 460 * @return the String value, or {@code null} if not present 461 * @throws ServletRequestBindingException a subclass of ServletException, 462 * so it doesn't need to be caught 463 */ 464 @Nullable 465 public static String getStringParameter(ServletRequest request, String name) 466 throws ServletRequestBindingException { 467 468 if (request.getParameter(name) == null) { 469 return null; 470 } 471 return getRequiredStringParameter(request, name); 472 } 473 474 /** 475 * Get a String parameter, with a fallback value. Never throws an exception. 476 * Can pass a distinguished value to default to enable checks of whether it was supplied. 477 * @param request current HTTP request 478 * @param name the name of the parameter 479 * @param defaultVal the default value to use as fallback 480 */ 481 public static String getStringParameter(ServletRequest request, String name, String defaultVal) { 482 String val = request.getParameter(name); 483 return (val != null ? val : defaultVal); 484 } 485 486 /** 487 * Get an array of String parameters, return an empty array if not found. 488 * @param request current HTTP request 489 * @param name the name of the parameter with multiple possible values 490 */ 491 public static String[] getStringParameters(ServletRequest request, String name) { 492 try { 493 return getRequiredStringParameters(request, name); 494 } 495 catch (ServletRequestBindingException ex) { 496 return new String[0]; 497 } 498 } 499 500 /** 501 * Get a String parameter, throwing an exception if it isn't found. 502 * @param request current HTTP request 503 * @param name the name of the parameter 504 * @throws ServletRequestBindingException a subclass of ServletException, 505 * so it doesn't need to be caught 506 */ 507 public static String getRequiredStringParameter(ServletRequest request, String name) 508 throws ServletRequestBindingException { 509 510 return STRING_PARSER.validateRequiredString(name, request.getParameter(name)); 511 } 512 513 /** 514 * Get an array of String parameters, throwing an exception if not found. 515 * @param request current HTTP request 516 * @param name the name of the parameter 517 * @throws ServletRequestBindingException a subclass of ServletException, 518 * so it doesn't need to be caught 519 */ 520 public static String[] getRequiredStringParameters(ServletRequest request, String name) 521 throws ServletRequestBindingException { 522 523 return STRING_PARSER.validateRequiredStrings(name, request.getParameterValues(name)); 524 } 525 526 527 private abstract static class ParameterParser<T> { 528 529 protected final T parse(String name, String parameter) throws ServletRequestBindingException { 530 validateRequiredParameter(name, parameter); 531 try { 532 return doParse(parameter); 533 } 534 catch (NumberFormatException ex) { 535 throw new ServletRequestBindingException( 536 "Required " + getType() + " parameter '" + name + "' with value of '" + 537 parameter + "' is not a valid number", ex); 538 } 539 } 540 541 protected final void validateRequiredParameter(String name, @Nullable Object parameter) 542 throws ServletRequestBindingException { 543 544 if (parameter == null) { 545 throw new MissingServletRequestParameterException(name, getType()); 546 } 547 } 548 549 protected abstract String getType(); 550 551 protected abstract T doParse(String parameter) throws NumberFormatException; 552 } 553 554 555 private static class IntParser extends ParameterParser<Integer> { 556 557 @Override 558 protected String getType() { 559 return "int"; 560 } 561 562 @Override 563 protected Integer doParse(String s) throws NumberFormatException { 564 return Integer.valueOf(s); 565 } 566 567 public int parseInt(String name, String parameter) throws ServletRequestBindingException { 568 return parse(name, parameter); 569 } 570 571 public int[] parseInts(String name, String[] values) throws ServletRequestBindingException { 572 validateRequiredParameter(name, values); 573 int[] parameters = new int[values.length]; 574 for (int i = 0; i < values.length; i++) { 575 parameters[i] = parseInt(name, values[i]); 576 } 577 return parameters; 578 } 579 } 580 581 582 private static class LongParser extends ParameterParser<Long> { 583 584 @Override 585 protected String getType() { 586 return "long"; 587 } 588 589 @Override 590 protected Long doParse(String parameter) throws NumberFormatException { 591 return Long.valueOf(parameter); 592 } 593 594 public long parseLong(String name, String parameter) throws ServletRequestBindingException { 595 return parse(name, parameter); 596 } 597 598 public long[] parseLongs(String name, String[] values) throws ServletRequestBindingException { 599 validateRequiredParameter(name, values); 600 long[] parameters = new long[values.length]; 601 for (int i = 0; i < values.length; i++) { 602 parameters[i] = parseLong(name, values[i]); 603 } 604 return parameters; 605 } 606 } 607 608 609 private static class FloatParser extends ParameterParser<Float> { 610 611 @Override 612 protected String getType() { 613 return "float"; 614 } 615 616 @Override 617 protected Float doParse(String parameter) throws NumberFormatException { 618 return Float.valueOf(parameter); 619 } 620 621 public float parseFloat(String name, String parameter) throws ServletRequestBindingException { 622 return parse(name, parameter); 623 } 624 625 public float[] parseFloats(String name, String[] values) throws ServletRequestBindingException { 626 validateRequiredParameter(name, values); 627 float[] parameters = new float[values.length]; 628 for (int i = 0; i < values.length; i++) { 629 parameters[i] = parseFloat(name, values[i]); 630 } 631 return parameters; 632 } 633 } 634 635 636 private static class DoubleParser extends ParameterParser<Double> { 637 638 @Override 639 protected String getType() { 640 return "double"; 641 } 642 643 @Override 644 protected Double doParse(String parameter) throws NumberFormatException { 645 return Double.valueOf(parameter); 646 } 647 648 public double parseDouble(String name, String parameter) throws ServletRequestBindingException { 649 return parse(name, parameter); 650 } 651 652 public double[] parseDoubles(String name, String[] values) throws ServletRequestBindingException { 653 validateRequiredParameter(name, values); 654 double[] parameters = new double[values.length]; 655 for (int i = 0; i < values.length; i++) { 656 parameters[i] = parseDouble(name, values[i]); 657 } 658 return parameters; 659 } 660 } 661 662 663 private static class BooleanParser extends ParameterParser<Boolean> { 664 665 @Override 666 protected String getType() { 667 return "boolean"; 668 } 669 670 @Override 671 protected Boolean doParse(String parameter) throws NumberFormatException { 672 return (parameter.equalsIgnoreCase("true") || parameter.equalsIgnoreCase("on") || 673 parameter.equalsIgnoreCase("yes") || parameter.equals("1")); 674 } 675 676 public boolean parseBoolean(String name, String parameter) throws ServletRequestBindingException { 677 return parse(name, parameter); 678 } 679 680 public boolean[] parseBooleans(String name, String[] values) throws ServletRequestBindingException { 681 validateRequiredParameter(name, values); 682 boolean[] parameters = new boolean[values.length]; 683 for (int i = 0; i < values.length; i++) { 684 parameters[i] = parseBoolean(name, values[i]); 685 } 686 return parameters; 687 } 688 } 689 690 691 private static class StringParser extends ParameterParser<String> { 692 693 @Override 694 protected String getType() { 695 return "string"; 696 } 697 698 @Override 699 protected String doParse(String parameter) throws NumberFormatException { 700 return parameter; 701 } 702 703 public String validateRequiredString(String name, String value) throws ServletRequestBindingException { 704 validateRequiredParameter(name, value); 705 return value; 706 } 707 708 public String[] validateRequiredStrings(String name, String[] values) throws ServletRequestBindingException { 709 validateRequiredParameter(name, values); 710 for (String value : values) { 711 validateRequiredParameter(name, value); 712 } 713 return values; 714 } 715 } 716 717}