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.beans.MutablePropertyValues; 022import org.springframework.lang.Nullable; 023import org.springframework.validation.BindException; 024import org.springframework.web.multipart.MultipartRequest; 025import org.springframework.web.util.WebUtils; 026 027/** 028 * Special {@link org.springframework.validation.DataBinder} to perform data binding 029 * from servlet request parameters to JavaBeans, including support for multipart files. 030 * 031 * <p>See the DataBinder/WebDataBinder superclasses for customization options, 032 * which include specifying allowed/required fields, and registering custom 033 * property editors. 034 * 035 * <p>Can also be used for manual data binding in custom web controllers: 036 * for example, in a plain Controller implementation or in a MultiActionController 037 * handler method. Simply instantiate a ServletRequestDataBinder for each binding 038 * process, and invoke {@code bind} with the current ServletRequest as argument: 039 * 040 * <pre class="code"> 041 * MyBean myBean = new MyBean(); 042 * // apply binder to custom target object 043 * ServletRequestDataBinder binder = new ServletRequestDataBinder(myBean); 044 * // register custom editors, if desired 045 * binder.registerCustomEditor(...); 046 * // trigger actual binding of request parameters 047 * binder.bind(request); 048 * // optionally evaluate binding errors 049 * Errors errors = binder.getErrors(); 050 * ...</pre> 051 * 052 * @author Rod Johnson 053 * @author Juergen Hoeller 054 * @see #bind(javax.servlet.ServletRequest) 055 * @see #registerCustomEditor 056 * @see #setAllowedFields 057 * @see #setRequiredFields 058 * @see #setFieldMarkerPrefix 059 */ 060public class ServletRequestDataBinder extends WebDataBinder { 061 062 /** 063 * Create a new ServletRequestDataBinder instance, with default object name. 064 * @param target the target object to bind onto (or {@code null} 065 * if the binder is just used to convert a plain parameter value) 066 * @see #DEFAULT_OBJECT_NAME 067 */ 068 public ServletRequestDataBinder(@Nullable Object target) { 069 super(target); 070 } 071 072 /** 073 * Create a new ServletRequestDataBinder instance. 074 * @param target the target object to bind onto (or {@code null} 075 * if the binder is just used to convert a plain parameter value) 076 * @param objectName the name of the target object 077 */ 078 public ServletRequestDataBinder(@Nullable Object target, String objectName) { 079 super(target, objectName); 080 } 081 082 083 /** 084 * Bind the parameters of the given request to this binder's target, 085 * also binding multipart files in case of a multipart request. 086 * <p>This call can create field errors, representing basic binding 087 * errors like a required field (code "required"), or type mismatch 088 * between value and bean property (code "typeMismatch"). 089 * <p>Multipart files are bound via their parameter name, just like normal 090 * HTTP parameters: i.e. "uploadedFile" to an "uploadedFile" bean property, 091 * invoking a "setUploadedFile" setter method. 092 * <p>The type of the target property for a multipart file can be MultipartFile, 093 * byte[], or String. The latter two receive the contents of the uploaded file; 094 * all metadata like original file name, content type, etc are lost in those cases. 095 * @param request the request with parameters to bind (can be multipart) 096 * @see org.springframework.web.multipart.MultipartHttpServletRequest 097 * @see org.springframework.web.multipart.MultipartFile 098 * @see #bind(org.springframework.beans.PropertyValues) 099 */ 100 public void bind(ServletRequest request) { 101 MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request); 102 MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class); 103 if (multipartRequest != null) { 104 bindMultipart(multipartRequest.getMultiFileMap(), mpvs); 105 } 106 addBindValues(mpvs, request); 107 doBind(mpvs); 108 } 109 110 /** 111 * Extension point that subclasses can use to add extra bind values for a 112 * request. Invoked before {@link #doBind(MutablePropertyValues)}. 113 * The default implementation is empty. 114 * @param mpvs the property values that will be used for data binding 115 * @param request the current request 116 */ 117 protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) { 118 } 119 120 /** 121 * Treats errors as fatal. 122 * <p>Use this method only if it's an error if the input isn't valid. 123 * This might be appropriate if all input is from dropdowns, for example. 124 * @throws ServletRequestBindingException subclass of ServletException on any binding problem 125 */ 126 public void closeNoCatch() throws ServletRequestBindingException { 127 if (getBindingResult().hasErrors()) { 128 throw new ServletRequestBindingException( 129 "Errors binding onto object '" + getBindingResult().getObjectName() + "'", 130 new BindException(getBindingResult())); 131 } 132 } 133 134}