前言

主要现在项目中使用的参数绑定五花八门的,搞得很头大,例如有些用字符串接收日期,用字符串接受数组等等,完全没有利用好 SpringMVC 的优势,这里自己也总结一下,免得到时又要百度谷歌查找。

以下实践的 Spring 版本是:5.2.7.RELEASE

一、SpringMVC 中不同类型的数据绑定

1.1、基础数据类型

  • 默认参数名
  // http://localhost:8080/baseType3?a=123
@GetMapping("/baseType")
@ResponseBody
public String baseType(int a) {
return "baseType " + a;
}
  • 使用@RequestParam 自定义请求参数名称
  //  http://localhost:8080/baseType3?b=123
@GetMapping("/baseType3")
@ResponseBody
public String baseType3(@RequestParam(value = "b", required = true) Integer a) {
return "baseType3 " + a;
}
  • 多个参数
  //  http://localhost:8080/baseType4?age=10&name=Java
@GetMapping("/baseType4")
public String baseType3(@RequestParam Integer age, String name) {
return "baseType4 age:" + age + " name="+name;
}

1.2、 对象类型

超过三个参数及以上,则推荐使用对象来接收传递的参数

  • 定义简单对象接收参数
  @Data //这里使用了 lombok 插件
public class User {
Integer id;
String name;
} // http://localhost:8080/objectType?id=1&name=Java
@GetMapping("/objectType")
public String objectType(User user) {
return "objectType " + user;
}
  • 内嵌对象接收参数
  @Data
public class Order {
Integer id;
User user;
} // http://localhost:8080/objectType2?id=1&user.name=Java&user.id=2
@GetMapping("/objectType2")
public String objectType2(Order order) {
return "objectType2 " + order;
}
  • 使用 DataBinder 解决不同对象,参数名相同覆盖问题

    • 定义对象
  @Data
public class Friend {
Integer id;
String name; //与User 对象name 名称冲突
} @Data
public class User {
Integer id;
String name;
}
  • InitBinder 配置

    在 Controller 中定义,只对当前 Controller 有效,也可以在 @ControllerAdvice 类中全局定义

/**
* 初始化绑定参数user 标识前缀
*
* @param binder
*/
@InitBinder("user")
public void initBinderUser(WebDataBinder binder) {
binder.setFieldDefaultPrefix("user.");
} /**
* 初始化绑定参数friend 标识前缀
*
* @param binder
*/
@InitBinder("friend")
public void initBinderFriend(WebDataBinder binder) {
binder.setFieldDefaultPrefix("friend.");
}
  • 编写请求
//http://localhost:8080/objectType3?name=Java  name会同时填充到User 和Friend对象上
//http://localhost:8080/objectType3?user.name=Java&friend.name=Python 分别填充数据到各自的对象中去
@GetMapping("/objectType3")
public String objectType3(User user, Friend friend) {
return "objectType3 user" + user + " friend " + friend;
}

1.3、 日期类型

日期类型的参数传递方式比较多,正式项目中建议统一规定日期类型的参数绑定的格式

1.3.1、使用时间戳传递(不是参数绑定方式)
// http://localhost:8080/dateType6?date=1628752881
@GetMapping("/dateType6")
public String dateType5(Long date) {
return "dateType6 date" + new Date(date);
}
1.3.2、使用字符串接收(不是参数绑定方式)
// http://localhost:8080/dateType7?date=2021-08-12
@GetMapping("/dateType7")
public String dateType7(String date) throws ParseException {
return "dateType7 date" + new SimpleDateFormat("yyyy-MM-dd").parse(date);
}
1.3.3、使用 SpringMVC 默认提供的 @DateTimeFormat (对于 json 参数无效)
// http://localhost:8080/dateType2?date1=2020-01-01
@GetMapping("/dateType2")
public String dateType2(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date1) {
return "dateType2 date " + date1;
}
1.3.4、使用 @InitBinder 注册转换器
  • 添加转换器
    /**
* 注册日期转换 date
*
* @param binder
*/
@InitBinder
public void initBinderDate(WebDataBinder binder) {
binder.addCustomFormatter(new Formatter<Date>() {
@Override
public Date parse(String text, Locale locale) throws ParseException {
System.out.println("InitBinder addCustomFormatter String to Date ");
return new SimpleDateFormat("yyyy-MM-dd").parse(text);
} @Override
public String print(Date date, Locale locale) {
System.out.println("InitBinder addCustomFormatter Date to String ");
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
});
}
  • 请求
// http://localhost:8080/dateType?date=2020-01-01
@GetMapping("/dateType")
public String dateType(Date date) {
return "dateType date" + date;
}
1.3.5、全局配置 Formatter

对于 json 参数(@RequestBody 修饰的参数)无效,优先级比 @DateTimeFormat 高

@Configuration
public class WebConfig implements WebMvcConfigurer { /**
* 注册 Converters 和 Formatters
*
* @param registry
*/
@Override
public void addFormatters(FormatterRegistry registry) {
//参数传出格式化
registry.addFormatter(new DateFormatter("yyyy-MM-dd"));
}
}
1.3.6、@JsonFormat 单独配置字段格式化

只对 @RequestBody 修饰的参数有效

  • 定义实体
@Data
public class UserDate { @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM")
private Date birthday;
}
  • 请求
/**
* http://localhost:8080/dateType4
* {
* "birthday": "2020-08"
* }
*/
@PostMapping("/dateType4")
@ResponseBody
public UserDate dateType4(@RequestBody UserDate userDate) {
return userDate;
}
1.3.7、全局配置 JSON 参数日期格式化

注意: 全局配置后,依然可以使用 @JsonFormat 注解,用来接收特殊的日期参数格式。

  • 配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
//指定时区
.timeZone(TimeZone.getTimeZone("GMT+8:00"))
//日期格式化
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
converters.add(0, new MappingJackson2HttpMessageConverter(builder.build()));
}
}
  • 实体
@Data
public class UserDate { @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM")
private Date birthday; private Date date;
}
  • 请求
/**
* http://localhost:8080/dateType4
* {
* "birthday": "2020-08",
* "date": "2021-08-13"
* }
*/
@PostMapping("/dateType4")
@ResponseBody
public UserDate dateType4(@RequestBody UserDate userDate) {
return userDate;
}

1.4、 复杂类型

复杂类型包括数组和集合类型,像 List、Set、Map。以下以 List 为例

  • 使用逗号分割形式
    /**
* 请求形式
* http://localhost:8080/complexType2_1?list=1,2,3
*/
@GetMapping("/complexType2_1")
public String complexType2_1(@RequestParam("list") List<String> list) {
return "complexType2_1 " + list;
}
  • 相同参数明传递多次
    /**
* 请求形式
* http://localhost:8080/complexType2?list=1&list=2
*/
@GetMapping("/complexType2")
public String complexType2(@RequestParam("list") List<String> list) {
return "complexType2 " + list;
}
  • 使用 JSON 字符串传递
/**
* 请求形式
* http://localhost:8080/complexType4
* <p>
* 请求体
* [1,2,3]
*/
@PostMapping("/complexType4")
public String complexType4(@RequestBody List<String> list) {
return "complexType4 " + list;
}

1.5、 特殊类型

  • xml
@Data
@XmlRootElement(name ="user")
public class User {
Integer id;
String name;
} /**
* http://localhost:8080/xmlType <?xml version="1.0" encoding="utf-8"?>
<user>
<id>1</id>
<name>Java</name>
</user>
*/
@PostMapping(path = "/xmlType", consumes = "application/xml;charset=UTF-8")
public String xmlType(@RequestBody User user) {
return "xmlType " + user;
}
  • json

/**
* 请求
* http://localhost:8080/jsonType
* 请求体
{
"id": 1,
"name": "Java"
}
*
* @RequestBody 不支持GET请求
*/
@PostMapping(value = "/jsonType", consumes = "application/json")
public String jsonType(@RequestBody User user) {
return "jsonType " + user;
}

二、了解底层实现

2.1、SpringMVC 方法参数绑定

2.1.1、认识 HandlerMethodArgumentResolver 接口
public interface HandlerMethodArgumentResolver {

	//该解析器是否支持parameter参数的解析
boolean supportsParameter(MethodParameter parameter); //从给定请求(webRequest)解析为参数值并填充到指定对象中
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
2.1.2、内置的 HandlerMethodArgumentResolver
//在初始化RequestMappingHandlerAdapter 时会默认加载参数解析器
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#afterPropertiesSet
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(); // Annotation-based argument resolution //处理 @RequestParam 注解标识的参数
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
//处理@RequestParam 注解标识的Map参数且不能指定参数名称
resolvers.add(new RequestParamMapMethodArgumentResolver());
//处理@PathVariable 注解标识路径参数 如/pathVariable/{a}
resolvers.add(new PathVariableMethodArgumentResolver());
//处理@PathVariable 注解标识的Map参数且不能指定参数名称
resolvers.add(new PathVariableMapMethodArgumentResolver()); //处理@MatrixVariable注解标识的参数
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false)); //处理@RequestBody 注解
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
//处理请求头
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
//处理Cookie 值
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver()); // Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // 添加自定义的解析器
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
} // Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers;
}
2.1.2、执行过程
  • 初始化解析器到 RequestMappingHandlerAdapter 中
// org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerAdapter
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcValidator") Validator validator) { RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(contentNegotiationManager);
adapter.setMessageConverters(getMessageConverters());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator)); //可以实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer接口
//设置自定义的参数解析器
adapter.setCustomArgumentResolvers(getArgumentResolvers()); adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
if (jackson2Present) {
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
configureAsyncSupport(configurer);
if (configurer.getTaskExecutor() != null) {
adapter.setTaskExecutor(configurer.getTaskExecutor());
}
if (configurer.getTimeout() != null) {
adapter.setAsyncRequestTimeout(configurer.getTimeout());
}
adapter.setCallableInterceptors(configurer.getCallableInterceptors());
adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
return adapter;
} // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#afterPropertiesSet
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache(); if (this.argumentResolvers == null) {
//获取默认解析器 和 自定义解析器
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
  • 寻找合适的解析器
//1. org.springframework.web.servlet.DispatcherServlet#doDispatch
//2. org.springframework.web.servlet.HandlerAdapter#handle
//3. org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
//4. org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取方法参数
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//判断是否支持解析该参数
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//HandlerMethodArgumentResolverComposite 组合模式
//使用具体HandlerMethodArgumentResolver 解析参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled...
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
  • 解析参数
// @RequestParam 注解的参数
// org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver#resolveArgument
//不同解析器实现不一样
@Override
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//根据参数定义创建一个NamedValueInfo对象
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
//如果参数是使用Optional包裹,则获取内嵌的参数对象
MethodParameter nestedParameter = parameter.nestedIfOptional();
// 处理参数名称
Object resolvedName = resolveStringValue(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
//解析请求参数值
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
} if (binderFactory != null) {
//创建WebDataBinder
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
//转换请求参数为对应方法形参
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
}
catch (ConversionNotSupportedException ex) {
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
}
//处理路径参数
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg;
}

2.2、WebDataBinder 原理

2.2.1、初始化 WebDataBinder 方式
  • @Controller 在每个控制器中定义(或者提取到 BaseController )
public class BaseController {
// @InitBinder 注解的方法,返回值需要声明为void
@InitBinder
public void initBinderUser(WebDataBinder binder) {
System.out.println("BaseController WebDataBinder 执行" );
}
} @RestController
public class DemoDataBindingController extends BaseController {
}
  • @ControllerAdvice 类 中定义,每个请求都会执行,适合全局配置
@ControllerAdvice
public class ControllerAdviceConfig { @InitBinder
public void initBinderUser(WebDataBinder binder) {
System.out.println("ControllerAdvice WebDataBinder 执行" );
}
}
  • 自定义 WebBindingInitializer
//默认实现 ConfigurableWebBindingInitializer
public interface WebBindingInitializer {
// org.springframework.web.bind.support.DefaultDataBinderFactory#createBinder 创建时调用
// 比@InitBinder 注解的方法先执行
void initBinder(WebDataBinder binder); @Deprecated
default void initBinder(WebDataBinder binder, WebRequest request) {
initBinder(binder);
}
}
@Configuration
public class CustomConfigurableWebBindingInitializer extends ConfigurableWebBindingInitializer { @Override
public void initBinder(WebDataBinder binder) {
super.initBinder(binder); System.out.println("CustomConfigurableWebBindingInitializer initBinder");
}
} //发起请求时,控制台输出
//CustomConfigurableWebBindingInitializer initBinder
//ControllerAdvice WebDataBinder 执行
2.2.2、WebDataBinder 有什么作用?
  • 用于绑定请求参数(Form 表单参数,query 参数)到模型对象中
  • 用于转换 字符串参数(请求参数、路径参数、header 属性、Cookie) 为 Controller 方法形参的对应类型
  • 格式化对象为指定字符串格式
2.2.3、WebDataBinder 执行过程
  • 定义初始化 WebDataBinder 方式(#2.2.1)
  • 创建 DataBinderFactory
//1. org.springframework.web.servlet.DispatcherServlet#doDispatch
//2. org.springframework.web.servlet.HandlerAdapter#handle
//3. org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
Class<?> handlerType = handlerMethod.getBeanType();
Set<Method> methods = this.initBinderCache.get(handlerType);
if (methods == null) {
// 查找@Controller中 @InitBinder 注解的方法
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
// Global methods first
// initBinderAdviceCache 在 RequestMappingHandlerAdapter#afterPropertiesSet 里初始化
// 1. 先加载 在@ControllerAdvice类定义的 @InitBinder 注解的方法
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
}
//2. 再加载@Controller中 @InitBinder 注解的方法
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
return createDataBinderFactory(initBinderMethods);
}
  • 执行 initBinder 方法
// org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver#resolveArgument
// org.springframework.web.bind.support.DefaultDataBinderFactory#createBinder
@Override
@SuppressWarnings("deprecation")
public final WebDataBinder createBinder(
NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception { WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
if (this.initializer != null) {
//执行 WebBindingInitializer 定义的initBinder方法
this.initializer.initBinder(dataBinder, webRequest);
}
//执行 @InitBinder 注解的方法
initBinder(dataBinder, webRequest);
return dataBinder;
}

到此,对 SpringMVC 的参数绑定讲解完成了。

项目地址

参考

【工作篇】再次熟悉 SpringMVC 参数绑定的更多相关文章

  1. SpringMVC参数绑定,这篇就够了!

    SpringMVC参数绑定,简单来说就是将客户端请求的key/value数据绑定到controller方法的形参上,然后就可以在controller中使用该参数了 下面通过5个常用的注解演示下如何进行 ...

  2. SpringMVC参数绑定(未完待续)

    1. Strut2与SpringMVC接收请求参数的区别 Struts2通过action类的成员变量接收SpringMVC通过controller方法的形参接收 2. SpringMVC参数绑定流程 ...

  3. 一篇文章搞定SpringMVC参数绑定

    SpringMVC参数绑定,简单来说就是将客户端请求的key/value数据绑定到controller方法的形参上,然后就可以在controller中使用该参数了 下面通过5个常用的注解演示下如何进行 ...

  4. [转载]SpringBoot系列: SpringMVC 参数绑定注解解析

    本文转载自 https://www.cnblogs.com/morethink/p/8028664.html, 作者写得非常好, 致谢! SpringMVC 参数绑定注解解析   本文介绍了用于参数绑 ...

  5. SpringMvc参数绑定出现乱码解决方法

    在SpringMvc参数绑定过程中出现乱码的解决方法 1.post参数乱码的解决方法 在web.xml中添加过滤器 <!-- 过滤器 处理post乱码 --> <filter> ...

  6. SpringMVC参数绑定学习总结【前后端数据参数传递】

    目录 1. 绑定机制 2. 支持的数据类型 3. 参数请求中文乱码解决 4.自定义类型转换器 5.最后参数绑定学习小结 SpringMVC作为Controller层(等价servlet和struts中 ...

  7. SpringMVC参数绑定(从请求中接受参数)

    参数绑定(从请求中接收参数) 1)默认类型: 在controller方法中可以有也可以没有,看自己需求随意添加. httpservletRqeust,httpServletResponse,httpS ...

  8. SpringMVC 参数绑定注解解析

    本文介绍了用于参数绑定的相关注解. 绑定:将请求中的字段按照名字匹配的原则填入模型对象. SpringMVC就跟Struts2一样,通过拦截器进行参数匹配. 代码在 https://github.co ...

  9. SpringMVC参数绑定总结

    springMvc作用:    a) 接收请求中的参数    b) 将处理好的数据返回给页面参数绑定(就是从请求中接收参数):    a) 默认支持的类型: request, response, se ...

随机推荐

  1. 滑动窗口通用解leetcode字符串匹配问题

    滑动窗口,这玩意解决一些字符串匹配的题目是真的挺好用的,虽然本质还是双指针. 思路: 1.维护一个窗口,不断的向右边移动 2.满足要求后,移动左边,当不满足时,跳出. 3.重复1,2.得出答案. 下面 ...

  2. WPF下如何使用TTF字体

    之前再写代码的时候如果遇到了图标,我都喜欢再资源文件下创建JPG或者PNG来作为图片. 但是随着TTF字体图标的普及,图标类型的的图片越来越多的被放入到TTF中. 这篇也主要是写再WPF下如何使用TT ...

  3. python使用笔记003-文件操作(一)

    文件操作分为: 1.打开文件,如果文件在当前目录下直接写文件名,如果文件在其他目录下写绝对路径 2.读/写文件 3.关闭文件 一.文件打开模式 # 'r':只读,文件读取后,会有文件指针记录读取文件的 ...

  4. iframe跨域访问出现的cookie问题,提供两种解决方案

    最近在java项目对接时出现的一个问题.A系统嵌入B系统页面时,使用iframe去嵌入B系统页面丢失sessionid,导致B系统认为是未进行登录的请求,从而跳转到了B系统登录页. 解决方法查看此博客 ...

  5. final修饰符(3)-基本类型变量和引用类型变量的区别

    final修饰基本类型变量 当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变 final修饰引用类型变量 当使用final修饰引用类型变量时,它保存的仅仅是一 ...

  6. 开源框架是如何使用设计模式的-MyBatis缓存机制之装饰者模式

    写在前面 聊一聊MyBatis是如何使用装饰者模式的,顺便回顾下缓存的相关知识,可以看看右侧目录一览内容概述. 装饰者模式 这里就不了它的概念了,总结下就是套娃.利用组合的方式将装饰器组合进来,增强共 ...

  7. P2491 消防/P1099 树网的核

    P2491 消防/P1099 树网的核 双倍经验,双倍快乐. 题意 在一个树上选择一段总长度不超过\(s\)的链使所有点到该链距离的最大值最小. 输出这个最小的值. 做法 Define:以下\(s\) ...

  8. 使用Visual Studio进行文件差异比较

    启动VS自带的文件差异比较工具,进行代码文本比较,省去安装第三方工具的麻烦. 一.启动VS命令窗口. 依次点击菜单[视图]>>[其它窗口]>>[命令窗口],如下图所示,启动命令 ...

  9. Vue--启动后到加载第一个页面的过程

    地址栏http://localhost:8088/#/填写密码登录后自动跳转到http://localhost:8088/#/home/msg/workerpush 一\ 得先跳转到login页面 { ...

  10. SQL SERVER 按时间计算每天某值的平均值

    在报表需求中,有针对求每天按时间分配数据的平均值,在经过查找后,找到一种方法,供参考. 1.新建视图 2.编写语句 SELECT  TOP (100) PERCENT AVG(dbo.漕盈日运行.CO ...