一、SpringMVC注解开发
1.1.创建一个WEB工程和导入jar包:
1.2.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>springmvc_demo02_annotation</display-name>
<filter>
<filter-name>characterEncoding</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>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 默认加载方式 默认加载必须规范: * 文件命名:servlet-name-servlet.xml====springmvc-servlet.xml
* 路径规范:必须在WEB-INF目录下面 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
|
1.3.配置springmvc.xml配置文件
在springmvc.xml配置文件中要开启spring的注解扫描、注解映射器和注解适配器、视图解析器;如果开启了springmvc的注解(开启注解通过<mvc:annotation-driven/>标签来开启),就不需要配置注解适配器和注解映射器。
<?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.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:component-scan base-package="com.lc"></context:component-scan>
<!-- 开启springmvc注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置注解处理器映射器 功能:寻找执行类Controller -->
<!--
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
-->
<!-- 配置注解处理器适配器 功能:调用controller方法,执行controller -->
<!--
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
-->
<!-- 配置sprigmvc视图解析器:解析逻辑试图 后台返回逻辑试图:index -->
<!--视图解析器解析出真正物理视图:前缀+逻辑试图+后缀====/WEB-INF/jsps/index.jsp -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsps/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
|
1.4.创建自定义Controller
@Controller//@Controller注解相当于在Spring配置文件中注册了该类的bean,因此该类由spring容器进行实例化
public class UserController {
//该方法是演示注解进行页面跳转
@RequestMapping("hello")//该注解映射到芳芳中
public String sayHello(){
return "index";//返回逻辑视图
}
}
|
1.5.RequestMapping注解和Controller注解
@Controller:用于标识是处理器类,表示把我当控制器对象交给spring来创建。
但是需要开启spring注解扫描:
<context:component-scan base-package="com.lc"></context:component-scan>
|
@RequestMapping:请求到处理器功能方法的映射规则;
如果在类上面加上RequestMapping注解;如:
@Controller//@Controller注解相当于在Spring配置文件中注册了该类的bean,因此该类由spring容器进行实例化
@RequestMapping("/user")//该注解相当于命名空间
public class UserController {
//该方法是演示注解进行页面跳转
@RequestMapping(value="hello")//该注解映射到芳芳中
public String sayHello(){
return "index";//返回逻辑视图
}
}
|
表示需要在访问该Controller时需要在url路径上加上:/user;访问该方法的全路径为:http://localhost/项目名称/user/hello.do
@RequestMapping(value="hello")和@RequestMapping(value="/hello.do")和@RequestMapping("/hello.do")一样。
@Controller//@Controller注解相当于在Spring配置文件中注册了该类的bean,因此该类由spring容器进行实例化
@RequestMapping("/user")//该注解相当于命名空间
public class UserController {
//该方法是演示注解进行页面跳转
@RequestMapping(value="hello",method=RequestMethod.POST)//该注解映射到芳芳中
public String sayHello(){
return "index";//返回逻辑视图
}
|
@RequestMapping(value="hello",method=RequestMethod.POST)代表访问该类下的sayHello方法必须为POST请求方式。
二、封装参数
2.1.封装int类型参数
接收参数方法:
//该方法演示封装int型参数,从前台(页面获取传回来的int参数)
@RequestMapping("getInteger")
public String getInteger(Integer id){
System.out.println(id);
return "index";//返回逻辑视图
}
|
访问:http://localhost/项目名称/user/getInteger.do?id=4
注意:方法中的参数名称要和页面传递到后台的参数名称一致,才能保证后台接收到参数。
2.2.封装String类型参数
接收参数方法:
//该方法演示从前台获取字符串类型参数
@RequestMapping("getString")
public String getString(String str){
System.out.println(str);
return "index";
}
|
访问:http://localhost/项目名称/user/getString.do?str=张三
2.3.接收数组
接收数组的方法:
//获取数组
@RequestMapping("/getArray")
public String getArrays(Integer[] ids){
for(Integer id :ids)
System.out.print(id+" ");
return "index";
}
|
页面传递数组参数:
<h1>后台通过数组接收数据</h1>
<form action="<%=path%>/user/getArray.do">
ID:<input type="checkbox" name="ids" value="1"/>1
<input type="checkbox" name="ids" value="2"/>2
<input type="checkbox" name="ids" value="3"/>3
<input type="checkbox" name="ids" value="4"/>4
<input type="submit" value="提交"/>
</form>
|
2.4.接收POJO类
接收方法:
//获取javabean数据
@RequestMapping("/getPojo.do")
public String getPojo(User user){
System.out.println(user);
return "index";//返回逻辑视图
}
|
页面传递POJO:
<form action="<%=path %>/user/getPojo.do">
姓名:<input type="text" name="username"/>
性别:<input type="text" name="sex"/>
地址:<input type="text" name="address"/>
<input type="submit" value="提交"/>
</form>
|
2.5.接收包装POJO
包装POJO:
public class UserCustom {
private User user;
private List<User> userList;
private Map<String ,Object> maps = new HashMap<>();
//省略getter和setter方法
}
|
接收方法:
//通过包装类获取数据
@RequestMapping("getUserCustom")
public String getUserCustom(UserCustom userCustom){
System.out.println(userCustom);
return "index";
}
|
页面:
<form action="<%=path %>/user/getUserCustom.do">
姓名:<input type="text" name="user.username"/>
性别:<input type="text" name="user.sex"/>
地址:<input type="text" name="user.address"/>
<input type="submit" value="提交"/>
</form>
|
2.6.接收List集合
接收方法:
//通过包装类型接收集合类型数据
@RequestMapping("getUserList")
public String getUserList(UserCustom userCustom){
System.out.println(userCustom.getUserList());
return "index";
}
|
页面:
<form action="<%=path %>/user/getUserList.do">
姓名:<input type="text" name="userList[0].username"/>
性别:<input type="text" name="userList[0].sex"/>
地址:<input type="text" name="userList[0].address"/>
姓名:<input type="text" name="userList[1].username"/>
性别:<input type="text" name="userList[1].sex"/>
地址:<input type="text" name="userList[1].address"/>
<input type="submit" value="提交"/>
</form>
|
2.7.接收Map集合
接收方法:
//通过包装类接收Map类型数据
@RequestMapping("getMap")
public String getMap(UserCustom userCustom){
System.out.println(userCustom.getMaps());
return "index";
}
|
页面:
<form action="<%=path %>/user/getMap.do">
姓名:<input type="text" name="maps['username']"/>
性别:<input type="text" name="maps['sex']"/>
地址:<input type="text" name="maps['address']"/>
<input type="submit" value="提交"/>
</form>
|
三、回显数据(通过Model对页面进行回显数据)
接收页面数据:
//向页面回显值
@RequestMapping("list")
public String listUser(UserCustom userCustom,Model model){
model.addAttribute("userList", userCustom.getUserList());
return "index";
}
|
传递页面数据:
<form action="<%=path %>/user/list.do">
id:<input type="text" name="userList[0].id"/>
姓名:<input type="text" name="userList[0].username"/>
性别:<input type="text" name="userList[0].sex"/>
地址:<input type="text" name="userList[0].address"/><br>
id:<input type="text" name="userList[1].id"/>
姓名:<input type="text" name="userList[1].username"/>
性别:<input type="text" name="userList[1].sex"/>
地址:<input type="text" name="userList[1].address"/><br>
id:<input type="text" name="userList[2].id"/>
姓名:<input type="text" name="userList[2].username"/>
性别:<input type="text" name="userList[2].sex"/>
地址:<input type="text" name="userList[2].address"/>
<input type="submit" value="提交"/>
</form>
|
回显页面:
<h1>回显数据</h1>
<table border="1">
<tr>
<td width="80">姓名</td>
<td width="80">年龄</td>
<td width="80">地址</td>
<td width="80">操作</td>
</tr>
<tr>
<td width="80">${userList[0].username }</td>
<td width="80">${userList[0].sex }</td>
<td width="80">${userList[0].address }</td>
<td width="80"><a href="<%=path%>/rest/user/updateById/${userList[0].id}">更新</a></td>
</tr>
<tr>
<td width="80">${userList[1].username }</td>
<td width="80">${userList[1].sex }</td>
<td width="80">${userList[1].address }</td>
<td width="80"><a href="<%=path%>/rest/user/updateById/${userList[1].id}">更新</a></td>
</tr>
<tr>
<td width="80">${userList[2].username }</td>
<td width="80">${userList[2].sex }</td>
<td width="80">${userList[2].address }</td>
<td width="80"><a href="<%=path%>/rest/user/updateById/${userList[2].id}">更新</a></td>
</tr>
</table>
|
四、SpringMVC的RESTFull映射风格
//修改
@RequestMapping("/updateById/{id}")
//@PathVariable注解就是把{id}映射到id上
public String updateById(@PathVariable Integer id){
System.out.println(id);
return "redirect:/user/list.do";//重定向到list.do
}
|
修改的url为:
<td width="80"><a href="<%=path%>/rest/user/updateById/${userList[2].id}">更新</a></td>
|
@PathVariable注解就是把url地址中的path一部分映射到方法的参数上。映射过程为:
由于使用REST风格,需要在web.xml配置文件中添加servletMapping:这样就可以让rest风格的请求也能被springmvc所接收。
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
|
五、转发和重定向
转发:forward
在本类进行转发可以写:
return "forward:list.do";或者return "forward:/本类根路径/lists.do";
跨类转发:
return "forward:/其他类的根路径/方法映射.do";
重定向:redirect
在本类进行重定向:return "redirect:list.do";或者return "redirect:/user/list.do";
跨类重定向:
return "redirect:/其他类根路径/其他类的方法.do";
六、@ResponseBody和@RequestBody注解
@ResponseBody把后台pojo转换json对象,返回到页面。
@RequestBody接受前台json数据,把json数据自动封装javaBean。
第一步:
由于这两个注解是对JavaBean和Json之间的转换,所以需要导入json的支持jar包:(在Java中常见的Json类库有:Gson、JSON-lib和Jackson等;Jackson相对来说比较高效;关于Jackson的使用:可以参考:https://www.cnblogs.com/winner-0715/p/6109225.html)jackson-core-asl.jar和jackson-mapper-asl.jar;
第二步:在springmvc中添加对json的支持;(在spring中是注解适配器在执行Cotroller类,因此需要在注解适配器中注入对json的支持)
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</property>
</bean>
|
如果是使用<mvc:annotation-driven/>标签开启了springmvc的注解,就不需要注入json的支持,因为springmvc默认是支持json的。
6.1.@ResponseBody注解
@ResponseBody功能:是把JavaBean转换为json数据
下面通过一个例子来对@ResponseBody注解进行演示:
//演示@ResponseBody
//该注解是把javaBean对象转换为json数据返回该请求页面
@RequestMapping("responseJson")
public @ResponseBody User responseJson(){
User user = new User();
user.setUsername("超哥");
user.setSex("男");
user.setAddress("武当山");
user.setId(1);
return user;
}
|
通过浏览器访问:
此时浏览器获取到的是json数据;
6.2.@RequestBody注解
@RequestBody注解功能:该注解的功能是把页面请求的json数据封装到JavaBean的属性中去。
//演示@RequestBody注解
//该注解是把前台传过来的json数据转换为javaBean对象
@RequestMapping("requestBody")
public String requestJson(@RequestBody User user){
System.out.println(user);
return "index";
}
|
页面请求传递json数据:
<script type="text/javascript" src="<%=path%>/js/jquery.js"></script>
<script type="text/javascript">
function postJson(){
var json = JSON.stringify({'username':'超哥','sex':'男','address':'武当山'});
$.ajax({
type:"POST",
url:"<%=path%>/user/requestBody.do",
contentType:"application/json;charset=utf-8",
data:json,
success:function(data){
}
},true);
};
</script>
<input type="button" value="发送json数据" οnclick="postJson();">
|
七、SpringMVC对多视图的支持
这里我们就通过springmvc对json和xml的支持来演示springmvc如何支持多视图;在前面我们已经导入了json支持的相关jar包,因此我们需要导入spring对xml的支持的jar包(spring-oxm.jar)
修改springmvc配置文件对xml的支持:
在配置文件中创建ContentNegotiatingViewResolver类来支持多视图,并给该类注入contentNegotiationManager和defaultViews属性;通过下面的配置支持json和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.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:component-scan base-package="com.lc"></context:component-scan>
<!-- 开启springmvc注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- springmvc配置对多视图提供支持 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<!-- 配置支持媒体类型 -->
<property name="contentNegotiationManager">
<bean class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes">
<props>
<prop key="json">application/json</prop>
<!-- 注入支持xml视图类型 -->
<prop key="xml">application/xml</prop>
</props>
</property>
</bean>
</property>
<!-- 指定默认视图 -->
<property name="defaultViews">
<!-- 配置支持多个默认视图 -->
<list>
<!-- 对json视图的支持 -->
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"></bean>
<!-- 对xml视图的支持 -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.lc.pojo.User</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
</bean>
<!-- 配置sprigmvc视图解析器:解析逻辑试图 后台返回逻辑试图:index -->
<!--视图解析器解析出真正物理视图:前缀+逻辑试图+后缀====/WEB-INF/jsps/index.jsp -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsps/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
|
第二步:编写Contoller类的方法:
//演示springmvc对多视图的支持
@RequestMapping("multiView")
public User multiView(){
User user = new User();
user.setUsername("超哥");
user.setSex("男");
user.setAddress("武当山");
user.setId(2);
return user;
}
|
第三步:对JavaBen类添加@XmlRootElement注解;
@XmlRootElement注解在WebService中就提到了的,该注解就是把JavaBean转换为xml格式的数据的映射方式。如果没有该注解会出现以下状况:
第四步:访问设置多视图是否有效;
首先访问xml视图:
其次访问json视图:
有关springmvc对其他的视图(例如pdf)后面我再去研究。
八、SpringMVC的拦截器
拦截器的作用一般都是用于拦截请求,既然是用来拦截请求,那么拦截器是在处理器映射器执行的时候进行拦截的。拦截器最常的应用是用来来接用户非法的用户。(例如:用户没有登录,访问需要登录的页面是拒绝请求的)
在springmvc中拦截器分为两种:局部拦截器和全局拦截器。
局部拦截器:针对某个HandlerMapping进行拦截,也只针对某个HandlerMapping有效。
全局拦截器:对所有的请求都有效。而不局限的作用于某一个HandlerMapping。
8.1.局部拦截器
在配置文件中配置局部拦截器:
handlerInterceptor1和handlerInterceptor2只对BeanNameUrlHandlerMapping的请求拦截有效。
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="handlerInterceptor1"/>
<ref bean="handlerInterceptor2"/>
</list>
</property>
</bean>
<bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
<bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>
|
创建拦截器:
自定义拦截器需要实现HandlerInterceptor接口并实现改接口里面的三个方法:preHandle、postHandle、afterCompletion;这三个方法分别都是在什么时候执行呢?
preHandle方法:该方法在执行Controller方法之前就调用执行。
postHandle方法:该方法在Controller方法执行后但还没有返回ModelAndView的时候执行。
afterCompletion方法:该方法在Controller执行并返回ModelAndView后执行;
注意:在springmvc规范中规定,如果执行了preHandler方法,afterCompletion方法必须执行。
Public class HandlerInterceptor1 implements HandlerInterceptor{
/**
* controller执行前调用此方法
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
@Override
Public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
Return false;
}
/**
* controller执行后但未返回视图前调用此方法
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
@Override
Public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub}
/**
* controller执行后且视图返回后调用此方法
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
@Override
Public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
|
8.2.全局拦截器
全局拦截器是拦截所有的请求;
配置全局拦截器方法:
<!--拦截器 -->
<mvc:interceptors>
<!--多个拦截器,顺序执行 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.lc.springmvc.filter.HandlerInterceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.lc.springmvc.filter.HandlerInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
|
上面的配置方式是使用打开注解的方式,这样就不需要创建注解映射器和注解适配器。那么如果我们不使用<mvc:annotation-driven/>标签,而使用手动配置注解映射器和注解适配器方式该如果加入全局拦截器呢?
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<list>
<ref bean="handlerInterceptor1"/>
<ref bean="handlerInterceptor2"/>
</list>
</property>
</bean>
<bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
<bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>
|
这里给一个判断非法用户登录的拦截器代码:
Public class LoginInterceptor implements HandlerInterceptor{
@Override
Public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//如果是登录页面则放行
if(request.getRequestURI().indexOf("login.action")>=0){
return true;
}
HttpSession session = request.getSession();
//如果用户已登录也放行
if(session.getAttribute("user")!=null){
return true;
}
//用户没有登录挑战到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
|