和大彪一起来学习-SpringMvc之第三回(注解使用详解)
2015-01-23 22:40
489 查看
简述:
在上一篇文章中,介绍了适配器和映射器的一些概念,这篇文章主要是介绍SpringMvc注解的使用,下面先从一个最简单注解程序开始,慢慢引入一些常用的注解(@Controller,@Component,@Service,@Repository,@RequestMapping,@InitBinder,
@RequestParam,@PathVariable,@RequestBody ,@ResponseBody)。
一、第一个注解项目
1.创建项目,加入Jar包,编写web.xml
可以加入第一篇文章里面给出的那些jar包,项目结构如下:web.xml编写如下,前面已经有介绍过了,这里直接贴图了。
2.编写springmvc-servlet.xml加入注解支持
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd "> <!-- 0.指定扫描 @Controller,@Component,@Service,@Repository之类Bean的路径--> <context:component-scan base-package="com.billstudy.springmvc"/> <!-- 1.注解映射器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 2.注解适配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" /> <!-- 小技巧:以上1、2可以直接使用 <mvc:annotation-driven />,这个配置已经包含上面两个bean配置,所以也能实现支持注解的效果 --> <!-- 3.视图解析器 最终路径为:prefix + Controller内返回逻辑视图名 + suffix 如:方法返回/hello,那么实际路径为:/WEB-INF/jsp/hello.jsp --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp" /> <property name="suffix" value=".jsp"/> </bean> </beans>3.编写Controller类
package com.billstudy.springmvc.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; /** * SpringMvc/Spring 企业开发常用注解使用演示 * @author Bill * @since V1.0 2015/01/23 */ /** 标明为Controller类,可以被Spring 扫描到,一般此类注解都作用于类上 ,与此相似的还有: * @Service : 一般用于MVC设计中M(model)层,也就是业务层 * @Repository : 一般用于DAO层,也就是数据访问层 * @Component : 仅仅表示一个组件 (Bean),比较泛化,当我们写了一个类不好定位其在MVC那层的时候,可以使用这个 * @Controller:一般用于MVC设计中C(Controller)层,也就是控制层 * **/ @Controller public class AnnotationDemoController{ @RequestMapping("/annotationTest01")/** 定义访问规则 **/ public ModelAndView annotationTest01(HttpServletRequest request,HttpServletResponse response){ ModelAndView result = new ModelAndView(); result.setViewName("/annotationTest01"); // 这里的ViewName,我们把它看成逻辑视图名,最终结合视图解析器,路径为:/WEB-INF/jsp/annotationTest01.jsp result.addObject("msg", "注解使用成功了!"); return result; } }
4.部署,测试
二、注解应用
1.@RequestMapping
使用方法1(路径映射):
【URL】加在Controller具体方法上,称为子路径映射。如:@RequestMapping("/annotationTest01"),这个时候若没有在类上用这个注解,那么可以直接通过【项目名/annotationTest01】访问这个方法了。若是类上面写了@RequestMapping("/parent"),那么这时候访问就是【项目名/parent/annotationTest01】了,也就是说类中所有的方法,都应该带上/parent,类上面我们称其为根路径映射。演示:
子路径:
jsp/result.jsp内容:
访问效果:
根路径:类上面写了,那么访问具体方法时,都要带上根路径。
访问测试:
使用方法2(URI
模板模式映射):
@RequestMapping(value="/parent/{id}"):{×××}占位符,请求的URL可以是“/parent/001”或“/parent/abc”,通过在方法中使用@PathVariable获取{×××}中的×××变量。若是有多个,则直接@RequestMapping(value="/parent/{id}/{name}/{age}")就可以了
演示:
使用方法3(请求方式限定):
也就是规定客户端请求的类型,如get/post,不按照要求来报 http405错误
下面使用Firefox的HttpRequest测试,我就不写form/表单测试了,效果都一样。
如果想让方法同时支持get/post,那么可以这么写:@RequestMapping(value="/postMethod",method={RequestMethod.POST,RequestMethod.GET}),就是写多个就可以了。
下面的注解解决了一些请求参数绑定,所以例子和请求参数一起测试。
三、注解配合请求实现参数绑定
默认支持(Java基本数据类型,HttpServletRequest 通过request对象获取请求信息HttpServletResponse 通过response处理响应信息 HttpSession 通过session对象得到session中存放的对象 Model 通过model向页面传递数据),若是页面是多个表单元素使用同一个name,那么就可以直接使用String[]接收值,这个和别的框架一样。没啥特别的。如果是Date类型,则需要注册转换器了,否则会报错,如下:
1.@InitBinder
下面,创建了几个类:package com.billstudy.springmvc.bean; import java.util.Date; /** * User Bean * @author Bill * @since V1.0 2015/01/25 */ public class User { private Integer id; private String name; private Integer age; private Boolean status; private Date birthday; public User() { // TODO Auto-generated constructor stub } public User(Integer id,String name, Integer age, Boolean status, Date birthday) { super(); this.id = id; this.name = name; this.age = age; this.status = status; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User [id=" + id + ", name=" + name + ", age=" + age + ", status=" + status + ", birthday=" + birthday + "]"; } public Boolean getStatus() { return status; } public void setStatus(Boolean status) { this.status = status; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } }
package com.billstudy.springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.billstudy.springmvc.bean.User; /** * 配合User bean演示相关注解使用 * @author Bill * @since V.10 2015/01/25 */ @Controller @RequestMapping("/user") public class UserController { /** * 测试用户信息注入 * @param user */ @RequestMapping("/userSave") public void userSave(User user){ System.out.println(user); } }
WebContent/user/userEdit.jsp
<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title></title> </head> <body bgcolor="#C7EDCC"> <form action="${pageContext.request.contextPath}/user/userSave.do" method="POST"> <input type="hidden" value="${user.id}" name="id"/> <div align="center"> <table border="2"> <tr> <td>姓名</td> <td><input name="name" value="${user.name}"/></td> </tr> <tr> <td>年龄</td> <td><input name="age" value="${user.age}"/></td> </tr> <tr> <td>状态</td> <td> <input name="status" type="radio" <c:if test="${user.status}">checked</c:if> value="true"/>true <input name="status" type="radio" <c:if test="${!user.status}">checked</c:if> value="false"/>false </td> </tr> <tr> <td>生日</td> <td><input name="birthday" value='<fmt:formatDate value="${user.birthday}" pattern="yyyy-MM-dd"/>'/></td> </tr> <tr> <td>操作</td> <td><input value="submit" type="submit"/></td> </tr> </table> </div> </form> </body> </html>下面打开页面测试,会发现500异常,原因是Date转换不支持。
异常:
这个时候,@InitBinder派上用场了。
在UserController中加上如下代码:
@InitBinder /* register Date parse support*/ public void bindBinbar(ServletRequestDataBinder binder){ binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));/** true:允许为空 **/ }再测一把,将表单提交
页面会报404错误,这个我们不管,因为方法没有返回值,它找的默认路径,默认路径没有对应的jsp页面,我们的关注点在参数自动绑定这块。可以看到参数已经绑定了,但是存在乱码,解决乱码:在web.xml加入org.springframework.web.filter.CharacterEncodingFilter的支持,如下
<!-- 解决POST 中文乱码 --> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>若是get乱码则可以修改Tomcat/server.xml的编码,或者在代码中对具体中文参数进行ISO-8859-1 To UTF-8的方法,个人偏向修改Tomcat编码,简单省事。
加入Filter之后,效果如下:
可以看到,我的名字没有乱码了。 这里可以看出,springmvc会将表单中的name绑定到方法参数中,和struts2不同的是。这里没有用对象.属性的方式,当然这里也支持。那就是复杂对象里面包含复杂对象的时候。如下面这个类的定义:
package com.billstudy.springmvc.bean; import java.util.Arrays; import java.util.List; import java.util.Map; /** * List , Map , String[] Test Bean * @author Bill * @since V1.0 2015/01/25 */ public class Other { private List<User> tUsers; private Map<String,Object> tMaps; private String[] tStrs; private User mainUser; public List<User> gettUsers() { return tUsers; } public void settUsers(List<User> tUsers) { this.tUsers = tUsers; } public Map<String, Object> gettMaps() { return tMaps; } public void settMaps(Map<String, Object> tMaps) { this.tMaps = tMaps; } public String[] gettStrs() { return tStrs; } public void settStrs(String[] tStrs) { this.tStrs = tStrs; } public Other(List<User> tUsers, Map<String, Object> tMaps, String[] tStrs) { super(); this.tUsers = tUsers; this.tMaps = tMaps; this.tStrs = tStrs; } public User getMainUser() { return mainUser; } public void setMainUser(User mainUser) { this.mainUser = mainUser; } public Other() { } }
这个对象中包含了User对象,我们暂且把它称为复杂对象。那么在页面想要给这里面的user注入值时,就可以使用mainUser.name/mainUser.age的方式了。可以看到,里面还有List,Map,String[]等类型的属性,这个下面也对其参数绑定进行演示。
添加页面:/WebContent/user/injectTest.jsp
<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title></title> </head> <body bgcolor="#C7EDCC"> <form action="${pageContext.request.contextPath}/user/inject.do" method="POST"> <input type="hidden" value="${user.id}" name="id"/> <div align="center" style="background-color: #1B7D00"> <h1>List test</h1><br/> <!-- List 使用[下标]的方式绑定值 --> 姓名 <input name="tUsers[0].name" /><br/> 年龄 <input name="tUsers[0].age" /><br/> 状态 <input name="tUsers[0].status" type="radio" value="true"/>true <input name="tUsers[0].status" type="radio" value="false"/>false<br/> 生日 <input name="tUsers[0].birthday" /><br/> <hr/> 姓名 <input name="tUsers[1].name" /><br/> 年龄 <input name="tUsers[1].age" /><br/> 状态 <input name="tUsers[1].status" type="radio" value="true"/>true <input name="tUsers[1].status" type="radio" value="false"/>false<br/> 生日 <input name="tUsers[1].birthday" /><br/> <hr/> 姓名 <input name="tUsers[2].name" /><br/> 年龄 <input name="tUsers[2].age" /><br/> 状态 <input name="tUsers[2].status" type="radio" value="true"/>true <input name="tUsers[2].status" type="radio" value="false"/>false<br/> 生日 <input name="tUsers[2].birthday" /><br/> <hr/> <h1>Map test</h1><br/> <!-- Map key value的形式,比较容易理解吧 --> Map key flyName :<input name="tMaps['flyName']" /><br/> Map key flyAge :<input name="tMaps['flyAge']" /><br/> Map key flyAddress :<input name="tMaps['flyAddress']" /><br/> <h1>String Array test</h1><br/> <!-- 这个就是同名的表单元素,在Controller中就是一个字符串数组,和request.getParameterValues()一个效果 --> <input name="tStrs" /> <input name="tStrs" /> <input name="tStrs" /> <input name="tStrs" /> <h2>mainUser 填写</h2> <div align="center"> <table border="2"> <tr> <td>姓名</td> <td><input name="mainUser.name" /></td> </tr> <tr> <td>年龄</td> <td><input name="mainUser.age" /></td> </tr> <tr> <td>状态</td> <td> <input name="mainUser.status" type="radio" />true <input name="mainUser.status" type="radio" />false </td> </tr> <tr> <td>生日</td> <td><input name="mainUser.birthday" /></td> </tr> </table> </div> 操作 <input value="submit" type="submit"/><br/> </div> </form> </body> </html>
录入参数如下:
控制台输出如下:
List<User> tUsers:[User [id=null, name=姓名1, age=10, status=false, birthday=Mon Nov 11 00:00:00 CST 1991], User [id=null, name=姓名2, age=22, status=true, birthday=Tue Nov 12 00:00:00 CST 1991], User [id=null, name=姓名3,
age=33, status=false, birthday=Wed Nov 13 00:00:00 CST 1991]]
Map<String,Object> tMaps:{flyAddress=上海, flyAge=20, flyName=飞机}
String[] tStrs:[数组值01, 数组值02, 数组值03, 数组值04]
User mianUser:User [id=null, name=mainUser用户, age=100, status=true, birthday=Sun Jan 03 00:00:00 CST 1993]
2.@RequestParam
绑定单个请求参数value:参数名字,即入参的请求参数名字,如value=“id”表示请求的参数区中的名字为id的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值
添加方法如下(报错的测试,大家可以自己去做):
/** * 用了defaultValue,其实required=true也不会报错,因为有默认值。请求时需要将id的值以userId=xx的形式提交,会自动将值绑定到形参id中 * @param model * @param id * @return */ @RequestMapping("/requestParamTest") public String requestParamTest(Model model,@RequestParam(defaultValue="520",required=true,value="userId")String id){ model.addAttribute("msg", "requestParamTest id:"+id); return "/result"; }
测试如下:
不传递值,使用默认值
传递值:
3.@RequestBody
@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上,下面演示将客户端传递过来的JSON转成Java对象。要使用这个注解,需要先加入两个jar包(jackson-core-asl-1.9.11.jar,jackson-mapper-asl-1.9.11.jar),同时需要在springmvc-servlet.xml适配器中加入对jackson的支持,修改之后如下:
<!-- 2.注解适配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" > <span style="color:#ff0000;"><property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /> </list> </property></span> </bean>
在UserController中加入方法:
/** * 演示JSON TO Java Object * @param user */ @RequestMapping("/requestBodyTest") public void requestBodyTest(@RequestBody User user){ System.out.println("user:"+user); }
利用HttpRequest测试:
控制台输出:
4.@ResponseBody
该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端加入方法如下:
测试效果:
5.@ModelAttribute
Model一般可以用于在方法中放置变量在View取值,这个注解可以帮助我们将一些通用的变量返回到View(页面)。很方便取值,如下演示。添加如下三个方法,2个添加参数,1个直接跳转到指定页面。测试能否取值
方法:
/** * 将key 为citys的数组对象传递到页面 * @return */ @ModelAttribute("citys") public String[] getCitys(){ return new String[]{"中国","美国","伊拉克","日本"}; } /** * 将key 为users的List<User>对象传递到页面 * @return */ @ModelAttribute("users") public List<User> getUsers(){ List<User> users = new ArrayList<User>(); for (int i = 0; i < 3; i++) { // 构造函数 : User(Integer id,String name, Integer age, Boolean status, Date birthday) users.add(new User(i,"测试姓名"+i,10+i,true,Calendar.getInstance().getTime())); } return users; } /** * 直接跳转到页面,不存放任何数据 * @return */ @RequestMapping("/toShowValue") public String toShowValue(){ return "/showValue"; }
页面:
<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>测试ModelAttribute</title> </head> <body> citys:<br/> <c:forEach items="${citys}" var="city"> ${city} </c:forEach><br/> Users:<br/> <c:forEach items="${users}" var="user"> ${user} <br/> </c:forEach> </body> </html>访问结果:
三、forward/redirect
转发/重定向。也就是在方法内部设置ViewName或者直接返回String时可以达到转发/重定向的效果。转发:方式相当于“request.getRequestDispatcher().forward(request,response)”,转发后浏览器地址栏还是原来的地址。转发并没有执行新的request和response,而是和转发前的请求共用一个request和response。所以转发前请求的参数在转发后仍然可以读取到
重定向:方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的request和response。
使用演示:
/** * 演示转发,重定向用法,看注释部分就好了 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String demoForwardRedirect(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{ // request.getRequestDispatcher("").forward(request,response); // 转发 // return "forward:/xx/xx.jsp"; // 转发 // response.sendRedirect("/xx/xx.jsp"); // 重定向 // return "redirect:/xx/xx.jsp"; // 重定向 return null; }
注解部分还有@CookieValue,@RequestHeader@RequestPart,这些就小伙伴们自己去研究看看吧。 哈哈,收工。读书去了
本文所有代码:点击下载本文代码
上面分享的这些注解你会用了吗? 这里是 热爱生活,热爱技术,喜欢交友的大彪
.
相关文章推荐
- 和大彪一起来学习-SpringMvc之第三回(注解使用详解) 分类: SpringMvc 2015-01-23 22:40 600人阅读 评论(0) 收藏
- 和大彪一起来学习-SpringMvc之第四回(拦截器使用)
- 和大彪一起来学习-SpringMvc之第四回(拦截器使用) 分类: SpringMvc 2015-02-04 20:09 572人阅读 评论(0) 收藏
- 和大彪一起来学习-SpringMvc之第四回(拦截器使用) 分类: SpringMvc 2015-02-04 20:09 571人阅读 评论(0) 收藏
- SpringMVC学习总结(七)——SpringMVC注解@..详解
- 和大彪一起来学习-SpringMvc之第一回(框架了解和第一个SpringMvc程序)
- JAVAEE之Spring学习(五)---SpringMVC注解实现功能的详解
- 和大彪一起来学习-SpringMvc之第一回(框架了解和第一个SpringMvc程序) 分类: SpringMvc 2015-01-14 21:08 636人阅读 评论(0) 收藏
- SpringMVC学习笔记(三)使用IntelliJ IDEA开发Spring MVC HelloWorld(注解配置SpringMVC)
- Spring MVC学习总结(18)——SpringMVC事务Transactional注解使用总结
- JAVAWEB开发之SpringMVC详解(一)——SpringMVC的框架原理、架构简介、与mybatis整合和注解方式的使用、
- 和大彪一起来学习-SpringMvc之第二回(控制器,适配器说明) 分类: SpringMvc 2015-01-18 22:21 623人阅读 评论(0) 收藏
- Spring及springmvc注解(annotation)使用详解
- SpringMVC学习(四)--常用注解标签详解
- JAVAWEB开发之SpringMVC详解(一)——SpringMVC的框架原理、架构简介、与mybatis整合和注解方式的使用、
- 【Java EE 学习 83 下】【SpringMVC】【使用注解替代已过时的API】【SpringMVC、Hibernate整合】
- 学习SpringMVC——通过注解使用SpringMVC
- java SpringMVC学习使用详解
- Spring学习笔记1之IOC详解尽量使用注解以及java代码
- 和大彪一起来学习-SpringMvc之第二回(控制器,适配器说明)