SpringMVC
简介
Servlet发展史
Struts1.x–>Struts2.x–>SpringMVC
springmvc:
第一个SpringMVC程序
jar
spring-aop.jar
spring-bean.jar
spring-context.jar
spring-core.jar
spring-web.jar
spring-webmvc.jar
commons-logging.jar
报错NoClassDefFoundError:缺少jar
Servet - Springmvc
jsp ->Servlet (Springmvc)->Jsp
url
springmvc配置文件 springmvc.xml
选中常用的命名空间:beans aop context mvc
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 扫描 有注解的包 -->
<context:component-scan base-package="org.lanqiao.handler"></context:component-scan>
<!--配置视图解析器(InternalResourceViewResolver)
配置的prefix和suffix会给所有返回的地址加上前缀/views/加上后缀.jsp。
例return "success"
实际的结果为/views/success.jsp
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
普通的servlet流程:
请求-url-pattern -交给对应的servlet去处理
如果现在想用springmvc,而不是普通的servlet,如何告知程序?-如何让springmvc 介入程序:
需要配置一个 Springmvc自带的servlet
通过以下配置,拦截所有请求,交给SpringMVC处理:web.xml
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
其中:
<url-pattern>.action</url-pattern>
/ :一切请求 ,注意不是 /*
/user :拦截以 /user开头的请求
/user/abc.do :只拦截该请求
.action :只拦截 .action结尾的请求
通过
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
指定springmvc配置文件的路径,如果要省略,必须放到 默认路径:
/WEB-INF/springDispatcherServlet-servlet.xml
严格的来说是
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
/WEB-INF/servetname的值-servlet.xml
请求
<a href="welcome">first springmvc - welcome</a>
servlet
@RequestMapping(value="welcome",method=RequestMethod.POST,params= {"name=zs","age!=23","!height"})//映射
public String welcome() {
return "success" ;// views/success.jsp
}
项目中同时兼容 springMVC和Servlet
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>.action</url-pattern>
</servlet-mapping>
@RequestMapping
映射是 去匹配@RequestMapping注解,可以和方法名、类名不一致,
//接口/类 注解 配置
@Controller
@RequestMapping(value="handler") //映射
public class SpringMVCHandler {
@RequestMapping(value="welcome")//映射
public String welcome() {
return "success" ;
}
}
默认值的属性为value
@RequestMapping(value="welcome")
@RequestMapping("welcome")
二者相等
此时请求的路径为
handler/welcome
先去找类前面的,再去找方法前面的,默认使用了 请求转发的 跳转方式,地址栏的地址没有改变
method
通过method指定 请求方式(get post delete put)
@RequestMapping(value="welcome",method=RequestMethod.POST)//映射
params
参数值
params= {"name"}
请求参数值中一定要有name属性
params= {"name=zs"}
请求参数值中一定要有name属性,并且参数值一定是zs params= {“name=zs”,“age!=23”})
name:必须有name=“zs”参数
age!=23 :
- 如果有name=“age”,则age值不能是23
要么没有age
params= {"name=zs","age!=23","!height"})
请求参数中不能有height
headers
请求头
headers= {"Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Encoding=gzip, deflate"}
多个参数使用,
隔开
ant风格的请求路径
? 单字符
* 任意个字符(0或多个)
** 任意目录
@RequestMapping(value="welcome3/a?c/test")
接受示例:
a href="welcome3/axc/test"
a href="welcome3/ayc/test"
@RequestMapping(value="welcome3/*/test")
接受示例:
a href="welcome3/abc/test"
a href="welcome3/xxx/test"
@RequestMapping(value="welcome3/**/test")
接受示例:
a href="welcome3/abc/xyz/abccc/test"
a href="welcome3/xxx/xxx/xxx/test"
@PathVariable
通过@PathVariable获取动态参数
传参
<a href="hander/welcome5/zs">
zs为传递的值
@RequestMapping(value="welcome5/{name}")
public String welcome5(@PathVariable("name") String name ) {
System.out.println(name);
return "success" ;
}
name的值为zs
REST风格 :软件编程风格
conf.xml快速生成配置文件
ctrl+/ 选择#dispatcherservlet
然后修改拦截请求,和配置文件的位置
Springmvc:
GET :查
POST :增
DELETE :删
PUT :改
delete与put
普通浏览器 只支持get
post
方式 ;其他请求方式 如 delelte
| put
请求是通过过滤器(HiddenHttpMethodFilter)新加入的支持。
过滤器拦截delelte|put请求的条件
请求方式为post
标签有隐藏域,并且隐藏域的name为_method,value为delete或put
<input type="hidden" name="_method" value="delete|put">
springmvc实现 :put|post请求方式的步骤
增加过滤器,web.xml
<!-- 增加HiddenHttpMethodFilte过滤器:目的是给普通浏览器 增加 put|delete请求方式 -->
<filter>
<filter-name>HiddenHttpMethodFilte</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilte</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
delete
表单
<form action="handler/testRest/1234" method="post">
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="删">
</form>
控制器
@RequestMapping(value="testRest/{id}",method=RequestMethod.DELETE)
public String testDelete(@PathVariable("id") Integer id) {
System.out.println("delete:删 " +id);
return "success" ;
}
put
表单
<form action="handler/testRest/1234" method="post">
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="改">
</form>
控制器
@RequestMapping(value="testRest/{id}",method=RequestMethod.PUT)
public String testPut(@PathVariable("id") Integer id) {
System.out.println("put:改 "+id);
return "success" ;
}
get
表单
<form action="handler/testRest/1234" method="get">
<input type="submit" value="查">
</form>
控制器
@RequestMapping(value="testRest/{id}",method=RequestMethod.GET)
public String testGet(@PathVariable("id") Integer id) {
System.out.println("get:查 " +id);
return "success" ;
}
post
表单
<form action="handler/testRest/1234" method="post">
<input type="submit" value="增">
</form>
控制器
@RequestMapping(value="testRest/{id}",method=RequestMethod.POST)
public String testPost(@PathVariable("id") Integer id) {
System.out.println("post:增 " +id);
return "success" ;
}
通过method=RequestMethod.DELETE
匹配具体的请求方式
此外,可以发现 ,当映射名相同时即@RequestMapping(value="testRest)
相同,可以通过method处理不同的请求。
处理delete|put的源码分析
过滤器中 处理put|delete请求的部分源码:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
requestToUse = new HttpMethodRequestWrapper(request, paramValue);
}
}
filterChain.doFilter(requestToUse, response);
}
原始请求:request,改请求默认只支持get\ post \ header]
但是如果 是”POST” 并且有隐藏域
<input type="hidden" name="_method" value="DELETE"/>
则,过滤器 将原始的请求 request加入新的请求方式DELETE,并将原始请求 转为 requestToUse 请求(request+Delete请求)
最后将requestToUse 放入 请求链中, 后续再事情request时 实际就使用改造后的 requestToUse
普通传值
表单
<form action="handler/testParam" method="get">
name:<input name="uname" type="text" />
<input type="submit" value="查">
</form>
控制器
@RequestMapping(value="testParam")
public String testParam(@RequestParam("uname") String name) {
String name = request.getParameter("uname");
System.out.println(name);
return "success" ;
}
前台传多个参数值,后台可以接收其中几个值,但是不可以接收多的值,即后台接收的的值,前台一定要发送;前台发送的值,后台可以不接收
@RequestParam("uname") String name,@RequestParam(value="uage",required=false,defaultValue="23")
设置默认值,不传的时候为23
@RequestParam("uname")
接受前台传递的值,等价于
request.getParameter("uname");
required=false:该属性 不是必须的。
defaultValue="23":默认值23
获取请求头信息 @RequestHeader
<a href="handler/testRequestHeader">testRequestHeader</a>
public String testRequestHeader(@RequestHeader("Accept-Language") String al ) {}
通过@RequestHeader("Accept-Language") String al
获取请求头中的Accept-Language
值,并将值保存再al变量中
通过mvc获取cookie值(JSESSIONID)
@CookieValue (前置知识: 服务端在接受客户端第一次请求时,会给该客户端分配一个session (该session包含一个sessionId)),并且服务端会在第一次响应客户端时 ,将该sessionId赋值给JSESSIONID 并传递给客户端的cookie中
<a href="handler/testCookieValue">testCookieValue</a><br/>
@RequestMapping(value="testRequestHeader")
public String testRequestHeader(@RequestHeader("Accept-Language") String al ) {
System.out.println( al);
return "success" ;
}
小结:
SpringMVC处理各种参数的流程/逻辑:
请求: 前端发请求a-> @RequestMappting(“a”)
处理请求中的参数xyz:
@RequestMappting("a")
public String aa(@Xxx注解("xyz") xyz)
{
}
使用对象(实体类Student)接受请求参数
public class Student {
private int id;
private String name;
private Address address ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
public class Address {
private String homeAddress ;
private String schoolAddress ;
public String getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress;
}
public String getSchoolAddress() {
return schoolAddress;
}
public void setSchoolAddress(String schoolAddress) {
this.schoolAddress = schoolAddress;
}
}
<form action="handler/testObjectProperties" method="post">
id:<input name="id" type="text" />
name:<input name="name" type="text" />
家庭地址:<input name="address.homeAddress" type="text" />
学校地址:<input name="address.schoolAddress" type="text" />
<input type="submit" value="查">
</form>
@RequestMapping(value="testObjectProperties")
public String testObjectProperties(Student student) {//student属性 必须 和 form表单中的属性Name值一致(支持级联属性)
/* 以前的方式
String name = request.getParameter("name");
int age= Integer.parseInt(request.getParameter("age")s) ;
String haddrss = request.getParameter("homeaddress");
String saddress = request.getParameter("schooladdress");
Address address = new Address();
address.setHomeAddress(haddrss);
address.setSchoolAddress(saddress);
Student student = new Student();
student.setName(name);
student.setAddress(address);
*/
System.out.println(student.getId()+","+student.getName()+","+student.getAddress().getHomeAddress()+","+student.getAddress().getSchoolAddress());
return "success" ;
}
@InitBinder注解
实现参数绑定
<form action="/testBean" method="post">
name: <input type="text" name="u.name"> <br>
age: <input type="text" name="u.age"> <br>
name: <input type="text" name="s.name"> <br>
age: <input type="text" name="s.age"> <br>
<input type="submit">
</form>
@InitBinder("user")
public void init1(WebDataBinder binder) {
binder.setFieldDefaultPrefix("u.");
}
@InitBinder("stu")
public void init2(WebDataBinder binder) {
binder.setFieldDefaultPrefix("s.");
}
@RequestMapping("/testBean")
public ModelAndView testBean(User user, @ModelAttribute("stu") Student stu) {
System.out.println(stu);
System.out.println(user);
String viewName = "success";
ModelAndView modelAndView = new ModelAndView(viewName);
modelAndView.addObject("user", user);
modelAndView.addObject("student", stu);
return modelAndView;
}
}
@InitBinder(“user”)括号内的参数为类的首字母小写(默认命名规则),也可以用@ModelAttribute(“stu”)做限定.
在SpringMVC中使用原生态的Servlet API
HttpServletRequest ,HttpServletResponse
<a href="handler/testServletAPI">testServletAPI</a>
@RequestMapping(value="testServletAPI")
public String testServletAPI(HttpServletRequest request,HttpServletResponse response) {
// request.getParameter("uname") ;
System.out.println(request);
return "success" ;
}
直接将 servlet-api中的类、接口等 写在springMVC所映射的方法参数中即可:
处理模型数据
如果跳转时需要带数据:V、M,则可以使用以下方式:
ModelAndView、ModelMap 、Map、Model -数据放在了request作用域
@SessionAttributes、@ModelAttribute
ModelAndView
<a href="handler/testModelAndView">testModelAndView</a>
@RequestMapping(value="testModelAndView")
public ModelAndView testModelAndView() {
//ModelAndView:既有数据,又有视图
//ModelAndView:Model -M View-V
ModelAndView mv = new ModelAndView("success");//view: views/success.jsp,仍然会加前缀和后缀
Student student = new Student() ;
student.setId(2);
student.setName("zs");
mv.addObject("student", student);//相当于request.setAttribute("student", student);
return mv;
}
取值
${requestScope.student.id } -${requestScope.student.name } <br/>
ModelMap
<a href="handler/testModelMap">testModelMap</a>
@RequestMapping(value="testModelMap")
public String testModelMap(ModelMap mm) {
Student student = new Student() ;
student.setId(2);
student.setName("zs");
mm.put("student2", student);//request域
return "success"; //view
}
${requestScope.student2.id } -${requestScope.student2.name } <br/>
Map
<a href="handler/testMap">testMap</a>
@RequestMapping(value="testMap")
public String testMap(Map<String,Object> m) {
Student student = new Student() ;
student.setId(2);
student.setName("zs");
m.put("student3", student);//request域
return "success";
}
${requestScope.student3.id } -${requestScope.student3.name }
Model
<a href="handler/testModel">testModel
@RequestMapping(value="testModel")
public String testModel(Model model) {
Student student = new Student() ;
student.setId(2);
student.setName("zs");
model.addAttribute("student4",student);//request域
return "success";
}
${requestScope.student4.id } -${requestScope.student4.name }
会将x对象 放入request域中
如何将上述数据放入session中
加上注解
@SessionAttributes(..)
在Handlee类前加注解
@SessionAttributes(value="student4")
如果要在request中存放student4对象,则同时将该对象 放入session域中
@SessionAttributes(types= {Student.class,Address.class})
如果要在request中存放Student类型的对象,则同时将该类型对象放入session域中
@ModelAttribute
- 经常在 更新时使用
在不改变原有代码的基础之上,插入一个新方法。
<form action="handler/testModelAttribute" method="post"> 编号:<input name="id" type="hidden" value="31" /> 姓名:<input name="name" type="text" /> <input type="submit" value="修改"> </form>
@ModelAttribute//在任何一次请求前,都会先执行@ModelAttribute修饰的方法 //@ModelAttribute 在请求 该类的各个方法前 均被执行的设计是基于一个思想:一个控制器 只做一个功能 public void queryStudentById(Map<String,Object> map) { //StuentService stuService = new StudentServiceImpl(); //Student student = stuService.queryStudentById(31); //模拟调用三层查询数据库的操作 Student student = new Student(); student.setId(31); student.setName("zs"); student.setAge(23); //map.put("student", student) ;//约定:map的key 就是方法参数 类型的首字母小写 map.put("stu", student) ;//约定:map的key 就是方法参数 类型的首字母小写 }
//修改:Zs-ls @RequestMapping(value="testModelAttribute") public String testModelAttribute(@ModelAttribute("stu")Student student) { student.setName(student.getName());//将名字修改为ls System.out.println(student.getId()+","+student.getName()+","+student.getAge()); return "success"; }
通过@ModelAttribute修饰的方法 ,会在每次请求前先执行; 并且该方法的参数map.put()可以将 对象 放入 即将查询的参数中;
必须满足的约定: map.put(k,v) 其中的k 必须是即将查询的方法参数的首字母小写
//map.put("student", student) ;
public String testModelAttribute(Student student)
如果不一致,需要通过@ModelAttribute声明。
map.put("stu", student);
public String testModelAttribute(@ModelAttribute("stu")Student student) {
一个Servlet 对应一个功能:
增删改查 对应于 4个Servlet
@ModelAttribute会在 该类的每个方法执行前 均被执行一次,因为使用时需要注意。
视图、视图解析器
流程
Controller返回值–>ModeAndView–>ViewResolver(视图解析器)–>视图view(渲染)(Jsp/PDF/Excel)
视图的顶级接口:
View
视图解析器顶级接口:
ViewResolver
常见的视图和解析器:
InternalResourceView、InternalResourceViewResolver
public class JstlView extends InternalResourceView:
springMVC解析jsp时 会默认使用InternalResourceView,如果发现Jsp中包含了jstl语言相关的内容,则自动转为JstlView。
JstlView: 可以解析jstl\实现国际化操作
国际化: 针对不同地区、不同国家 ,进行不同的显示
中国: 欢迎
美国: welcome
具体实现国际化步骤:
创建资源文件
基名_语言_地区.properties 基名_语言.properties
中国
i18n_zh_CH.properties
resource.welcome=你好 resource.exist=退出
i18n_en_US.properties
resource.welcome=WELCOME resource.exist=EXIST
i18n.properties
xxx
系统会先查询i18n_zh_CH.properties文件中的内容,如果其他文件中没有设置一些属性的值,则在i18n.properties中寻找
文件中存放的是ASCLL值,如果输入时,没有进行转化,可以使用jdk中的工具:
cd到jdk安装位置/bin native2ascii.exe回车 输入要转化的值 回车
然后将转换后的值放入文件中
i18n:internationalization的首末字符i和n,18为中间的字符数
配置springmvc.xml,加载资源文件
<!-- 加载国际化资源文件 --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="i18n"></property> </bean>
ResourceBundleMessageSource会在springmvc响应程序时 介入(解析国际化资源文件)
springmvc在启动时,会自动查找一个id=“messageSource”的bean,如果有 则自动加载
通过jstl使用国际化
jar
jstl.jar standar.jar
导入命名空间success.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="fmt" %>
使用
<fmt:message key="resources.welcome"></fmt:message> <fmt:message key="resources.exit"></fmt:message>
ResourceBundleMessageSource:在MVC响应时介入,因此不能直接访问success.jsp,需要响应请求后访问
<a href="handler/testI18n">testI18n</a>
@RequestMapping(value="testI18n") public String testI18n() { return "success"; }
InternalResourceViewResolver其他功能:
<mvc:view-controller ...>
index.jsp -> Controller(@RequsetMapping("a")) ->succes.jsp
要用SpringMVC实现:index.jsp -> succes.jsp :
<a href="handler/testMvcViewController">testMvcViewController</a>
配置,springMVC.xml
<!--view-name会被视图解析器 加上前缀、后缀 -->
<mvc:view-controller path="handler/testMvcViewController" view-name="success"/>
以上注解 ,会让所有的请求 转入<mvc:..>
标签中匹配映射地址,而会忽略调@RequsetMapping();(controller)
如果想让 @RequsetMapping(“a”) 和<mvc:..>
共存,则需要加入一个注解:
<!--此配置是SpringMVC的基础配置,很功能都需要通过该注解来协调 -->
<mvc:annotation-driven></mvc:annotation-driven>
指定请求方式
指定跳转方式: 请求转发:地址栏不改变
return "forward:/views/success.jsp";
重定向:地址栏改变 return “redirect:/views/success.jsp”;
forward: redirect: ,需要注意 此种方式,不会被视图解析器加上前缀(/views)、后缀(.jsp)
处理静态资源:
html css js 图片 视频
动态(百度:天气 ):可以与用户交互、因为时间/地点的不同 而结果不同的内容
在SpringMVC中,如果直接访问静态资源:404 。
原因:之前将所有的请求 通过通配符/
拦截,进而交给 SPringMVC的入口DispatcherServlet去处理:找该请求映射对应的 @requestMapping
http://localhost:8888/SpringMVCProject/img.png
@RequsetMapping("img.png")
return sucess
解决:如果是 需要mvc处理的,则交给@RequsetMapping(“img.png”)处理;如果不需要springmvc处理,则使用 tomcat默认的Servlet去处理。
tomcat默认的Servlet去处理:如果有 对应的请求拦截,则交给相应的Servlet去处理;如果没有对应的servlet,则直接访问。
tomcat默认的Servlet在哪里?
在tomcat配置文件\conf\web.xml中
解决静态资源方案:如果有springmvc对应的@requestMapping则交给spring处理;如果没有对应@requestMapping,则交给服务器tomcat默认的servlet去处理 :
实现方法,只需要增加2个注解即可 springmvc.xml:
<!-- 该注解 会让 springmvc: 接收一个请求,并且该请求 没有对应的@requestmapping时,将该请求 交给服务器默认的servlet去处理(直接访问) -->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<mvc:annotation-driven></mvc:annotation-driven>
总结:要让springmvc访问静态资源,只需要加入以下2个注解:
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<mvc:annotation-driven></mvc:annotation-driven>
类型转换
Spring自带一些 常见的类型转换器
public String testDelete(@PathVariable("id") String id)
既可以接受int类型数据id 也可以接受String类型的id
可以自定义类型转换器
编写 自定义类型转器的类 (实现Converter接口)
//将字符串变成Student public class MyConverter implements Converter<String,Student>{ @Override public Student convert(String source) {//source:2-zs-23 //source接受前端传来的String:2-zs-23 String[] studentStrArr = source.split("-") ; Student student = new Student(); student.setId( Integer.parseInt( studentStrArr[0]) ); student.setName(studentStrArr[1]); student.setAge(Integer.parseInt(studentStrArr[2] )); return student; } }
配置:将MyConverter加入到springmvc中
将 自定义转换器 纳入SpringIOC容器
<!-- 1将 自定义转换器 纳入SpringIOC容器 --> <bean id="myConverter" class="org.lanqiao.converter.MyConverter"></bean>
将myConverter再纳入 SpringMVC提供的转换器Bean
<!-- 2将myConverter再纳入 SpringMVC提供的转换器Bean --> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <ref bean="myConverter"/> </set> </property> </bean>
将conversionService注册到annotation-driven中
<!-- 3将conversionService注册到annotation-driven中 --> <!--此配置是SpringMVC的基础配置,很功能都需要通过该注解来协调 --> <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
测试转换器:
<form action="handler/testConverter" method="post">
学生信息:<input name="studentInfo" type="text" /><!-- 2-zs-23 -->
<input type="submit" value="转换">
</form>
@RequestMapping(value="testConverter")
public String testConverter(@RequestParam("studentInfo") Student student) {// 前端:2-zs-23
System.out.println(student.getId()+","+student.getName()+","+student.getAge());
return "success";
}
其中@RequestParam("studentInfo")
是触发转换器的桥梁:
@RequestParam("studentInfo")
接收的数据 是前端传递过来的:2-zs-23
,但是需要将该数据赋值给修饰的目的对象Student
;因此SPringMVC可以发现 接收的数据 和目标数据不一致,并且 这两种数据分别是 String
、Student
,正好符合public Student convert(String source)
转换器。因此将类型进行转换
数据格式化
主要用于对数字和日期的转换
SimpleDateForamt sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
SPringMVC提供了很多注解,方便我们数据格式化
@DateTimeFormat(pattern="yyyy-MM-dd")
@NumberFormat(parttern="###,#")
实现步骤:
1. 配置,springMVC.xml
xml
<!-- 配置 数据格式化 注解 所依赖的bean -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
</bean>
2. 通过注解使用
Student.java
```java
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday ;// 2018-12-13
@NumberFormat(pattern="###,#")
private int id;
```
格式化:前台传递来的数据,将前台传递来到数据 固定为yyyy-MM-dd
当输入格式不正确时会报错
测试
<form action="handler/testDateTimeFormat" method="post">
编号:<input name="id" type="text" value="31" />
姓名:<input name="name" type="text" />
出生日期:<input name="birthday" type="text" />
<input type="submit" value="修改">
</form>
@RequestMapping(value="testDateTimeFormat")
//如果Student格式化出错,会将错误信息 传入result中,这样控制台会显示错误信息,但是前端不显示了,类似异常处理,将异常进行了处理
public String testDateTimeFormat(Student student , BindingResult result) {
System.out.println(student.getId()+","+student.getName()+","+student.getBirthday());
if(result.getErrorCount() >0) {
for(FieldError error: result.getFieldErrors() ) {
System.out.println(error.getDefaultMessage());
}
}
return "success";
}
在配置时发现格式化和类型转换所用到的类为
FormattingConversionServiceFactoryBean
ConversionServiceFactoryBean
因此可以将类型转化在格式化中配置,即FormattingConversionServiceFactoryBean
:既可以实现格式化、又可以实现类型转换
由
<!--
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter"/>
</set>
</property>
</bean>
-->
整合到
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter"/>
</set>
</property>
</bean>
错误消息:
上面我们可知,发生异常时在控制台打印后就不在页面打印了,此时想要两处都提示:
思路:将异常信息传到前端页面中即可
@RequestMapping(value="testDateTimeFormat")//如果Student格式化出错,会将错误信息 传入result中
public String testDateTimeFormat(@Valid Student student, BindingResult result ,Map<String,Object> map) {
//System.out.println(student.getId()+","+student.getName()+","+student.getBirthday());
if(result.getErrorCount() >0) {
for(FieldError error: result.getFieldErrors() ) {
System.out.println(error.getDefaultMessage());
map.put("errors", result.getFieldErrors() ) ;//将错误信息传入requset域中的errors中
// result.getFieldErrors().get(0).getDefaultMessage()
}
}
return "success";
}
<c:forEach items="${requestScope.errors}" var="error">
${error.getDefaultMessage()}<br/>
</c:forEach>
取值时使用了jstl表达式,因此需要配置
jar包
jstl.jar standaed.jar
引入jstl标签库xx.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
public String testDateTimeFormat(Student student, BindingResult result ,Map<String,Object> map) {}
需要验证的数据是 Student中的birthday, SPringMVC要求 如果校验失败 则将错误信息 自动放入 该对象之后紧挨着的 BindingResult
中。即Student student
, BindingResult result之
间 不能有其他参数。
如果要将控制台的错误消息 传到jsp中显示,则可以将 错误消息对象放入request域中,然后 在jsp中 从request中获取。
数据校验
JSR303
Hibernate Validator
Hibernate Validator 是JSR 303的扩展。Hibernate Validator 提供了 JSR 303中所有内置的注解,以及自身扩展的4个注解
使用Hibernate Validator步骤:
jar
(注意各个jar之间可能存在版本不兼容)
hibernate-validator-5.0.0.CR2.jar classmate-0.8.0.jar jboss-logging-3.1.1.GA.jar
validation-api-1.1.0.CR1.jar hibernate-validator-annotation-processor-5.0.0.CR2.jar
配置springMVC.xml
<mvc:annotation-driven ></mvc:annotation-driven>
此时mvc:annotation-driven
的作用:要实现Hibernate Validator/JSR303 校验(或者其他各种校验),必须实现SpringMVC提供的一个接口:ValidatorFactory
springMVC已经帮我们写了一个ValidatorFactory
的实现类LocalValidatorFactoryBean
<mvc:annotation-driven ></mvc:annotation-driven>
会在springmvc容器中 自动加载一个LocalValidatorFactoryBean类,因此可以直接实现数据校验。
直接使用注解
在属性前加注解
public class Student { @Past//当前时间以前 private Date birthday ; }
在校验的Controller中 ,给校验的对象前增加 @Valid
public String testDateTimeFormat(@Valid Student student, BindingResult result ,Map<String,Object> map) {}
Ajax请求SpringMVC,并且返回JSON格式的数据
jar
jackson-annotations-2.8.9.jar
jackson-core-2.8.9.jar
jackson-databind-2.8.9.jar
ajax请求
<script type="text/javascript" src="js/jquery-1.8.3.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#testJson").click(function(){
//通过ajax请求springmvc
$.post(
"handler/testJson",//服务器地址
//{"name":"zs","age":23}
function(result){//服务端处理完毕后的回调函数 List<Student> students, 加上@ResponseBody后, students实质是一个json数组的格式
for(var i=0;i<result.length ;i++){
alert(result[i].id +"-"+result[i].name +"-"+result[i].age);
}
}
);
});
});
@ResponseBody//告诉SpringMVC,此时的返回 不是一个 View页面,而是一个 ajax调用的返回值(Json数组)
@RequestMapping(value="testJson")
public List<Student> testJson() {
//Controller-Service-dao
//StudentService studentService = new StudentServiceImp();
//List<Student> students = studentService.qeuryAllStudent();
//模拟调用service的查询操作
Student stu1 = new Student(1,"zs",23);
Student stu2 = new Student(2,"ls",24);
Student stu3 = new Student(3,"ww",25);
List<Student> students = new ArrayList<>();
students.add(stu1) ;
students.add(stu2) ;
students.add(stu3) ;
return students;
}
SpringMVC实现文件上传
和Servlet方式的本质一样,都是通过
commons-fileupload.jar和commons-io.jar
SpringMVC可以简化文件上传的代码,但是必须满足条件:实现MultipartResolver
接口 ;而该接口的实现类SpringMVC也已经提供了CommonsMultipartResolver
具体步骤:(直接使用CommonsMultipartResolver
实现上传)
1. jar包
commons-fileupload.jar、commons-io.jar
配置
CommonsMultipartResolver
将其加入SpringIOC容器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"></property> <!-- 上传单个文件的最大值,单位Byte;如果-1,表示无限制 --> <property name="maxUploadSize" value="104857600"></property> </bean>
配置
CommonsMultipartResolver
,用于实现文件上传 将其加入SpringIOC容器.springIoc容器在初始化时,会自动寻找一个
Id="multipartResolver"
的bean,并将其加入Ioc容器处理方法
<form action="handler/testUpload" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> 描述:<input name="desc" type="text" /> <input type="submit" value="上传"> </form>
//文件上传处理方法 @RequestMapping(value="testUpload") //abc.png public String testUpload(@RequestParam("desc") String desc , @RequestParam("file") MultipartFile file ) throws IOException { System.out.println("文件描述信息:"+desc); //jsp中上传的文件:file InputStream input = file.getInputStream() ;//IO String fileName = file.getOriginalFilename() ; OutputStream out = new FileOutputStream("d:\\"+fileName) ; byte[] bs = new byte[1024]; int len = -1; while(( len = input.read(bs)) !=-1 ) { out.write(bs, 0, len); } out.close(); input.close(); //将file上传到服务器中的 某一个硬盘文件中 System.out.println("上传成功!"); return "success"; }
框架: 将原来自己写的1000行代码,变成:框架帮你写900行,剩下100行自己写
控制器:handler servlet controller action
拦截器
拦截器的原理和过滤器相同。
SpringMVC:要想实现拦截器,必须实现一个接口
HandlerInterceptor
编写拦截器
implements HandlerInterceptor
拦截器一
public class MyInterceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截请求"); // return true;//true:拦截操作之后,放行 ;false:拦截之后不放行,请求终止; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("拦截响应"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("视图(jsp)被渲染完毕"); } }
拦截器二
public class MySecondInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("第二个拦截器,拦截请求...22222"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("第二个拦截器,拦截响应...22222"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("第二个拦截器,afterCompletion"); } }
配置
将自己写的拦截器 配置到springmvc中(spring)
<!-- 将自己写的拦截器 配置到springmvc中(spring);默认拦截全部请求 --> <mvc:interceptors> <!--拦截一切请求时放在这 <bean class="org.lanqiao.interceptor.MySecondInterceptor"></bean> --> <!-- 配置具体的拦截路径,二者取交集 --> <mvc:interceptor> <!-- 指定拦截的路径,基于ant风格 --> <mvc:mapping path="/**"/> <!-- 指定拦不截的路径 --> <mvc:exclude-mapping path="/handler/testUpload"/> <bean class="org.lanqiao.interceptor.MyInterceptor"></bean> </mvc:interceptor> <!-- 配置具体的拦截路径 --> <mvc:interceptor> <!-- 指定拦截的路径,基于ant风格 --> <mvc:mapping path="/**"/> <!-- 指定拦不截的路径 --> <mvc:exclude-mapping path="/handler/testUpload"/> <bean class="org.lanqiao.interceptor.MySecondInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
拦截器1拦截请求- 拦截器2拦截请求 - 请求方法 - 拦截器2处理相应-拦截器1处理相应- 只会被 最后一个拦截器的afterCompletion()拦截
如果有多个拦截器,则每个拦截器的preHandle
postHandle
都会在相应时机各被触发一次;但是afterCompletion
, 只会执行最后一个拦截器的该方法。
异常处理
SpringMVC实现异常处理的顶级接口
HandlerExceptionResolver
该接口的每个实现类 都是异常的一种处理方式:
ExceptionHandlerExceptionResolver
主要提供了@ExceptionHandler
注解,并通过该注解处理异常
controller中出现异常
@RequestMapping("testExceptionHandler")
public String testExceptionHandler() {
//try {
System.out.println( 1/0 );//
//}catch(ArithmeticException e) e
//}catch(Exception e) e
return "success" ;
}
controller中定义捕获异常的方法
//该方法 可以捕获本类中 抛出的ArithmeticException异常,并返回error页面,将错误信息传递给error页面
@ExceptionHandler({ArithmeticException.class})
public ModelAndView handlerArithmeticException(ArithmeticException e) {
ModelAndView mv = new ModelAndView("error");
System.out.println(e +"============");
mv.addObject("er", e) ;
return mv;
}
error获取异常信息
${requesrScope.e}
数组越界异常
@RequestMapping("testExceptionHandler2")
public String testExceptionHandler2() {
int[] nums = new int[2];
System.out.println(nums[2]);//ArrayIndexOutOfBoundsException
return "success" ;
}
//该方法 可以捕获本类中 抛出的ArithmeticException异常
@ExceptionHandler({ArithmeticException.class,ArrayIndexOutOfBoundsException.class})
public ModelAndView handlerArithmeticException(Exception e) {
ModelAndView mv = new ModelAndView("error");
System.out.println(e +"============");
mv.addObject("er", e) ;
return mv;
}
@ExceptionHandler
标识的方法的参数 必须在异常类型(Throwable或其子类) ,不能包含其他类型的参数
异常处理路径:最短优先
如果有方法抛出一个ArithmeticException异常,而该类中 有2个对应的异常处理方法:
@ExceptionHandler({Exception.class })
public ModelAndView handlerArithmeticException2(Exception e) {}
@ExceptionHandler({ArithmeticException.class })
public ModelAndView handlerArithmeticException1(Exception e) {}
则优先级: 最短优先。
@ExceptionHandler默认只能捕获 当前类中的异常方法。
如果发生异常的方法 和处理异常的方法 不在同一个类中:@ControllerAdvice
//@ControllerAdvice
public class MyExceptionHandler {//不是控制器,仅仅是 用于处理异常的类
将处理异常的方法放到该类中
@ExceptionHandler({Exception.class })
public ModelAndView handlerArithmeticException2(Exception e) {
ModelAndView mv = new ModelAndView("error");
System.out.println(e +"============"+"该@ControllerAdvice中的异常处理方法,可以处理任何类中的异常");
mv.addObject("er", e) ;
return mv;
}
}
总结:如果一个方法用于处理异常,并且只处理当前类中的异常:@ExceptionHandler
如果一个方法用于处理异常,并且处理所有类中的异常: 类前加@ControllerAdvice
、 处理异常的方法前加@ExceptionHandler
ResponseStatusExceptionResolver
自定义异常显示页面@ResponseStatus
@ResponseStatus(value=HttpStatus.FORBIDDEN,reason="数组越界222!!!")
public class MyArrayIndexOutofBoundsException extends Exception {//自定义异常
}
@RequestMapping("testMyException")
public String testMyException(@RequestParam("i") Integer i) throws MyArrayIndexOutofBoundsException {
if(i == 3) {
throw new MyArrayIndexOutofBoundsException();//抛出异常
}
return "success" ;
}
@ResponseStatus也可以标志在方法前:
@RequestMapping("testMyException2")
public String testMyException2(@RequestParam("i") Integer i) {
if(i == 3) {
return "redirect:testResponseStatus" ;//跳转到某一个 异常处理方法里
}
return "success" ;
}
@ResponseStatus(value=HttpStatus.CONFLICT ,reason="测试。。。")
@RequestMapping("testResponseStatus")
public String testResponseStatus() {
return "success" ;
}
DefaultHandlerExceptionResolver
SPringMVC在一些常见异常的基础上(300 500 405),新增了一些异常,例如:
* @see org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
* @see #handleNoSuchRequestHandlingMethod
* @see #handleHttpRequestMethodNotSupported :如果springmvc的处理方法限制为post方式,如果实际请求为get,则会触发此异常显示的页面
* @see #handleHttpMediaTypeNotSupported
* @see #handleMissingServletRequestParameter
* @see #handleServletRequestBindingException
* @see #handleTypeMismatch
* @see #handleHttpMessageNotReadable
* @see #handleHttpMessageNotWritable
* @see #handleMethodArgumentNotValidException
* @see #handleMissingServletRequestParameter
* @see #handleMissingServletRequestPartException
* @see #handleBindException
SimpleMappingExceptionResolver
通过配置来实现异常的处理
@RequestMapping(value="testSimpleMappingExceptionResolver")
public String testSimpleMappingExceptionResolver() {
System.out.println(1/0);
return "success" ;
}
<!-- SimpleMappingExceptionResolver:以配置的方式 处理异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 如果发生异常,异常对象会被保存在 exceptionAttribute的value值中;并且会放入request域中 ;异常变量的默认值是 exception-->
<!--<property name="exceptionAttribute" value="exception"></property>-->
<property name="exceptionMappings">
<props>
<!-- 相当于catch(ArithmeticException ex){ 跳转:error } -->
<prop key="java.lang.ArithmeticException">
error
</prop>
<prop key="java.lang.NullPointerException">
error
</prop>
</props>
</property>
</bean>
${requestScope.exception}
表单标签:
启动tomcat报错:
Caused by: java.lang.IllegalArgumentException: More than one fragment with the name [spring_web] was found. This is not legal with relative ordering. See section 8.2.2 2c of the Servlet specification for details.
需要在web.xml添加标签
<absolute-ordering/>
自定义标签el/ jstl
Spring EL : 1. 支持各种类型的请求方式(查询doGet增 加doPost、删除doDelete 、修改doPut) 2. 可以将对象和表单绑定起来;对象的属性–表单path值 一一对应
IDEA开发springmvc
SpringMVC项目:
选择Springmvc:自动下载springmvc相关的jar
处理Jar :artifacts - fix : miss all…
开发代码:
引入标签库
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
使用:
类
public class Persion {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
表单
<form:form>
姓名:<form:input path="name"/><br>
年龄:<form:input path="age"/>
<input type="submit" value="提交">
</form:form>
控制器
@Controller
@RequestMapping("/FormDemo")
public class FormDemo {
public String testForm(Map<String,Object> map){
Persion per = new Persion();
per.setAge(23);
per.setName("zs");
map.put("command", per);//将per放入了request域中的command中
return "forward:/views/springForm.jsp";
}
}
<form id="command">
:SpringMVC标签会默认自动从名为”command”的对象中获取值,因此传值时将值放入command中
如果在map.put()时,名字不是command,则需要手工指定
<form:form commandName="person">
或
<form:form modelAttribute="person">
则传值时
map.put("person", per);//将per放入了request
各种表单的提交方式
编写method属性
<form:form action="FormDemo/testMethod" method="post"> <input type="submit" value="增加"> </form:form> <form:form action="FormDemo/testMethod" method="delete"> <input type="submit" value="删除"> </form:form> <form:form action="FormDemo/testMethod" method="put"> <input type="submit" value="修改"> </form:form> <form:form action="FormDemo/testMethod" method="get"> <input type="submit" value="查询"> </form:form>
@RequestMapping(value = "/testMethod",method = RequestMethod.POST) public String testPost(){ System.out.println("post"); return "/index.jsp"; } @RequestMapping(value = "/testMethod",method = RequestMethod.DELETE) public String testDelete(){ System.out.println("delete"); return "/index.jsp"; } @RequestMapping(value = "/testMethod",method =RequestMethod.PUT) public String testPut(){ System.out.println("put"); return "/index.jsp"; } @RequestMapping(value = "/testMethod",method = RequestMethod.GET) public String testGet(){ System.out.println("get"); return "/index.jsp"; }
配置过滤器
<!--增加过滤器 支持delete和put请求--> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
HiddenHttpMethodFilter会将全部请求中名为”method”的隐藏域进行Put|Delete处理
可以配置
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
<init-param>
<param-name>methodParam</param-name>
<param-value>myMethod</param-value>
</init-param>
</filter>
指定要处理的隐藏的名字
<form action="FormDemo/testMethod" method="post">
<input type="hidden" name="myMethod" value="delete">
<input type="submit" value="修改">
</form>
如果是使用的是SpringMvc标签:
method="put|delete"
如果不是SpringMVC标签,是传统的htnl标签
method="post"
<input type="hidden" name="myMethod" value="delete|put">
checkbox
自动绑定request域中的值
通过boolean值绑定
@RequestMapping("/testForm2") public String testForm2(Map<String,Object> map){ Persion per = new Persion(); //per.setAge(23); //per.setName("zs"); per.setSex(false); map.put("per", per); return "springForm"; //return "forward:/views/springForm.jsp"; }
<form:form commandName="per" action="textForm2"> <for:checkbox path="sex"/> <input type="submit" value="提交"> </form:form>
绑定集合(有值的打上勾)
@RequestMapping("/testForm3")
public String testForm3(Map<String,Object> map){
Persion per = new Persion();
List<String> hobbirs=new ArrayList<>();
hobbirs.add("football");
hobbirs.add("basketball");
per.setHobbies(hobbirs);
map.put("per", per);//将per放入了request域中
return "springForm";
}
<form:form commandName="per" action="textForm3">
<form:checkbox path="hobbies" value="football"></form:checkbox>
<form:checkbox path="hobbies" value="basketball"></form:checkbox>
<form:checkbox path="hobbies" value="pingpang"></form:checkbox>
<input type="submit" value="提交">
</form:form>
(了解)嵌套对象的toString()返回值
@RequestMapping("/testForm4")
public String testForm4(Map<String,Object> map){
Persion per = new Persion();
Other other = new Other();
per.setOther(other);
map.put("per", per);//将per放入了request域中
return "springForm";
}
<form:form commandName="per" action="textForm">
<form:checkbox path="other" value="football"></form:checkbox>
<form:checkbox path="other" value="basketball"></form:checkbox>
<form:checkbox path="other" value="pingpang"></form:checkbox>
<input type="submit" value="提交">
</form:form>
public class Other {
@Override
public String toString() {
return "pingpang";
}
}
path:选中的选项(选中)
item:所有的选项 a,b ,c d:如果是list,set,数组,则标签名默认就是选项值,如果想自定义标签名需要使用map
@RequestMapping("/testForm5")
public String testForm5(Map<String,Object> map){
Persion per = new Persion();
List<String> hobbies=new ArrayList<>();
hobbies.add("football");
hobbies.add("basketball");
per.setHobbies(hobbies);
map.put("per", per);//将per放入了request域中
List<String> allHobbies=new ArrayList<>();
allHobbies.add("football");
allHobbies.add("basketball");
allHobbies.add("pingpang");
allHobbies.add("aaa");
allHobbies.add("bbb");
map.put("allHobbies", allHobbies);
return "springForm";
}
<form:form commandName="per" action="textForm">
<form:checkboxes path="hobbies" items="${allHobbies}"/>
<input type="submit" value="提交">
</form:form>
加载所有的选项allHobbies并且选中选中的hobbies
指定标签名
可以通过 Map<Value值,标签名>
Map<String, String> allHobbiesMap = new HashMap<>();
allHobbiesMap.put("football","足球");
allHobbiesMap.put("basketball","篮球");
allHobbiesMap.put("pingpang","乒乓球");
allHobbiesMap.put("aaa","bbb");
map.put("allHobbies", allHobbiesMap);
单选按钮
@RequestMapping("/testForm6")
public String testForm6(Map<String,Object> map){
Persion per = new Persion();
per.setCountry("China");
map.put("per", per);//将per放入了request域中
return "springForm";
}
<form:form commandName="per" action="textForm">
中国:<form:radiobutton path="country" value="China"/>
美国:<form:radiobutton path="country" value="USE"/>
<input type="submit" value="提交">
</form:form>
一批
@RequestMapping("/testForm7")
public String testForm7(Map<String,Object> map){
Persion per = new Persion();
per.setFavouriteBall("pingpang");
map.put("per", per);//将per放入了request域中
Map<String, String> allHobbiesMap = new HashMap<>();
allHobbiesMap.put("football","足球");
allHobbiesMap.put("basketball","篮球");
allHobbiesMap.put("pingpang","乒乓球");
allHobbiesMap.put("aaa","bbb");
map.put("allBallMap", allHobbiesMap);
return "springForm";
}
<form:form commandName="per" action="textForm">
<form:radiobuttons path="favouriteBall" items="${allBallMap}"/>
<input type="submit" value="提交">
</form:form>
属性delimiter
可以指定选项与选项之间的分隔符
<form:radiobuttons path="favouriteBall" items="${allBallMap}" delimiter="、"/>
select
写法一
<form:form commandName="per" action="textForm">
<form:select path="favouriteBall" items="${allBallMap}"/>
<input type="submit" value="提交">
</form:form>
写法二:指定选定的值,选项是自己写的,后端不传所有的选项只传favouriteBall
<form:form commandName="per" action="textForm">
<form:select path="favouriteBall">
<form:option value="football">足球11</form:option>
<form:option value="basketball">篮球11</form:option>
<form:option value="pingpang">乒乓球11</form:option>
<form:option value="aaa">bbb11</form:option>
</form:select>
<input type="submit" value="提交">
</form:form>
写法三
<form:form commandName="per" action="textForm">
<form:select path="favouriteBall">
<form:options items="${allBallMap}"></form:options>
<%-- <form:option value="football">足球11</form:option>
<form:option value="basketball">篮球11</form:option>
<form:option value="pingpang">乒乓球11</form:option>
<form:option value="aaa">bbb11</form:option>--%>
</form:select>
<input type="submit" value="提交">
</form:form>
@RequestMapping("/testForm7")
public String testForm7(Map<String,Object> map){
Persion per = new Persion();
per.setFavouriteBall("pingpang");
map.put("per", per);//将per放入了request域中
Map<String, String> allHobbiesMap = new HashMap<>();
allHobbiesMap.put("football","足球");
allHobbiesMap.put("basketball","篮球");
allHobbiesMap.put("pingpang","乒乓球");
allHobbiesMap.put("aaa","bbb");
map.put("allBallMap", allHobbiesMap);
return "springForm";
}
如果方式三和方式二同时存在则会优先选择方式二
如果方式一和方式二同时存在则会优先选择一
如果普通方式和springmvc方式同时存在则会使用springmvc的方式,普通的option没有匹配的功能。