SpringMVC
学习过的mvc框架:Struts2
springMVC就是类似于Struts2的mvc框架,属于SpringFrameWork的后续产品。
为什么学SpringMVC?
SpringMVC与Struts2区别 | |||
对比项目 | SrpingMVC | Struts2 | 优势 |
国内市场情况 | 有大量用户,一般新项目启动都会选用springmvc | 有部分老用户,老项目组,由于习惯了,一直在使用。 | 国内情况,springmvc的使用率已经超过Struts2 |
框架入口 | 基于servlet | 基于filter | 本质上没太大优势之分,只是配置方式不一样 |
框架设计思想 | 控制器基于方法级别的拦截,处理器设计为单实例 | 控制器基于类级别的拦截, 处理器设计为多实例 | 由于设计本身原因,造成了Struts2,通常来讲只能设计为多实例模式,相比于springmvc设计为单实例模式,Struts2会消耗更多的服务器内存。 |
参数传递 | 参数通过方法入参传递 | 参数通过类的成员变量传递 | Struts2通过成员变量传递参数,导致了参数线程不安全,有可能引发并发的问题。 |
与spring整合 | 与spring同一家公司,可以与spring无缝整合 | 需要整合包 | Springmvc可以更轻松与spring整合 |
-
- 开发环境
Jdk:jdk1.7
Eclipse:mars
Tomcat:apache-tomcat-7
spring:4.2.4
-
- 开发步骤
- 创建Dynamic web项目
- 开发步骤
课堂上起的项目名字:01-springmvc
-
-
- 导入springmvc的jar包
-
位置:\01课前资料\jar包\springmvc独立运行
-
-
- 编写TestController类
-
public class HelloController {
@RequestMapping("hello")
public ModelAndView hello(){
System.out.println("hello springmvc....");
//创建ModelAndView对象
ModelAndView mav = new ModelAndView();
//设置模型数据
mav.addObject("msg", "hello springmvc...");
//设置视图名字
mav.setViewName("/WEB-INF/jsp/hello.jsp");
return mav;
}
}
-
-
- 创建hello.jsp页面
-
-
-
- 创建与配置springmvc.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置@Controller处理器,包扫描器 -->
<context:component-scan base-package="com.itheima.springmvc.controller" />
</beans>
-
-
- 在web.xml中配置前端控制器
-
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载springmvc核心配置文件 -->
<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>*.action</url-pattern>
</servlet-mapping>
-
-
- 启动项目通过浏览器测试
-
http://localhost:8080/hello.aciton
-
- 小结-springmvc代码执行流程
- 完成商品列表加载
复制第一个项目01-springmvc,粘贴在本项目目录下改名:02-springmvc,删掉web.xml核心控制器的配置,重新配置一次(多练习一次)。
-
- 复制itemList.jsp到新工程中
目录:\01课前资料\案例\jsp
-
- 创建Item的pojo
public class Item {
// 商品id
private int id;
// 商品名称
private String name;
// 商品价格
private double price;
// 商品创建时间
private Date createtime;
// 商品描述
private String detail;
创建带参数的构造器
set/get。。。
}
-
- 编写ItemController
public class ItemController {
@RequestMapping("itemList")
public ModelAndView itemList(){
ModelAndView mav = new ModelAndView();
List<Items> itemList = new ArrayList<Items>();
itemList.add(new Items(1, "冰箱", 1999.0, new Date(), "质量不错"));
itemList.add(new Items(2, "冰箱2", 1999.0, new Date(), "质量不错2"));
itemList.add(new Items(3, "冰箱3", 1999.0, new Date(), "质量不错3"));
itemList.add(new Items(4, "冰箱4", 1999.0, new Date(), "质量不错4"));
itemList.add(new Items(5, "冰箱5", 1999.0, new Date(), "质量不错5"));
//设置商品数据
mav.addObject("itemList", itemList);
//设置视图名字
mav.setViewName("/WEB-INF/jsp/itemList.jsp");
return mav;
}
}
-
- 启动项目通过浏览器测试
- SpringMVC架构
- 框架默认加载组件
-
-
- 处理器映射器与处理器适配器
- 处理器映射器
- 处理器映射器与处理器适配器
-
从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射。
<!-- 配置处理器映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
-
-
-
- 处理器适配器
-
-
从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。
<!-- 处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
-
-
-
- 小结
-
-
映射器与适配器必需配套使用,如果映射器使用了推荐的RequestMappingHandlerMapping,适配器也必需使用推荐的RequestMappingHandlerAdapter。
-
-
-
- 注解驱动
-
-
<!-- 注解驱动配置,代替映射器与适配器的单独配置,同时支持json响应(推荐使用) -->
<mvc:annotation-driven />
-
-
- 视图解析器
-
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置视图响应的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 配置视图响应的后缀 -->
<property name="suffix" value=".jsp" />
</bean>
-
- 总结-springMVC架构
- SpringMVC与Mybatis整合
创建Web新工程:03-springmvc-mybatis
- 参考思路与我提供的代码工程,自己动手搭建新工程。
- 整合功能主要是把商品列表加载,从数据库中查出。
- Dao开发可以用Mybatis逆向工程。
-
- 思路
Dao层:
- SqlMapConfig.xml,空文件即可。需要文件头。
- applicationContext-dao.xml。
- 数据库连接池
- SqlSessionFactory对象,需要spring和mybatis整合包下的。
- 配置mapper文件扫描器。
Service层:
- applicationContext-service.xml包扫描器,扫描@service注解的类。
- applicationContext-trans.xml配置事务。
Controller层:
Springmvc.xml
- 包扫描器,扫描@Controller注解的类。
- 配置注解驱动。最新的三大组件
- 视图解析器
Web.xml
- 配置spring容量监听器
- 配置前端控制器
- 参数绑定
- 默认支持的参数类型
基于完成需求:点击修改商品时,打开商品编辑页面,展示商品信息
/**
* 演示springmvc默认参数的传递
* 跳转修改商品信息页面
* @return
*/
@RequestMapping("itemEdit")
public ModelAndView itemEdit(HttpServletRequest request,HttpServletResponse response,HttpSession session){
ModelAndView mav = new ModelAndView();
//request获取参数
String id = request.getParameter("id");
System.out.println("id为:" + id);
//其它对象输出
System.out.println("response对象:" + response);
System.out.println("session对象:" + session);
//查询商品信息
Item item = itemServices.getItemById(new Integer(id));
//设置商品数据返回页面
mav.addObject("item", item);
//设置视图名称
mav.setViewName("itemEdit");
return mav;
}
-
- 绑定简单参数
/**
* 演示简单参数传递
* 跳转修改商品信息页面
* @RequestParam用法:入参名字与方法名参数名不一致时使用{
* value:传入的参数名,required:是否必填,defaultValue:默认值
* }
*
*/
@RequestMapping("itemEdit")
public ModelAndView itemEdit(@RequestParam(value="id",required=true,defaultValue="1")Integer ids){
ModelAndView mav = new ModelAndView();
//查询商品信息
Item item = itemServices.getItemById(ids);
//设置商品数据返回页面
mav.addObject("item", item);
//设置视图名称
mav.setViewName("itemEdit");
return mav;
}
-
- Model/ModelMap
/**
* 演示返回String,通过Model/ModelMap返回数据模型
* 跳转修改商品信息页面
* @param id
* @return
*/
@RequestMapping("itemEdit")
public String itemEdit(@RequestParam("id")Integer ids,Model m,ModelMap model){
//查询商品信息
Item item = itemServices.getItemById(ids);
//通过Model把商品数据返回页面
model.addAttribute("item", item);
//返回String视图名字
return "itemEdit";
}
下面这种情况页面的name 跟 参数名要一样
-
- 绑定pojo对象
要点:表单提交的name属性必需与pojo的属性名称一致。
/**
* 演示传递pojo参数
* 更新商品信息
* @return
*/
@RequestMapping("updateItem")
public String updateItem(Item item,Model model){
//更新商品
itemServices.update(item);
//返回商品模型
model.addAttribute("item", item);
//返回担任提示
model.addAttribute("msg", "修改商品成功");
//返回修改商品页面
return "itemEdit";
}
-
- 绑定包装的pojo
要点:通过点(.)传递属性。
-
-
- pojo:
-
-
-
- controller代码:
-
/**
* 演示包装pojo传递
* @param vo
* @return
*/
@RequestMapping("queryItem")
public String queryItem(QueryVo vo){
//打印传入参数
System.out.println(vo);
//返回视图
return "itemList";
}
-
-
- jsp修改:
-
-
- 乱码解决
- 高级参数绑定
- 数组类型的参数绑定
基于批量删除商品操作完成参数传递。
Jsp修改
控制器修改
/**
* 包装pojo传递演示
* 第二天,演示数组参数的传递与List的传递
* @param vo
* @return
*/
@RequestMapping("queryItem")
public String queryItem(QueryVo vo, Integer[] ids) {
System.out.println(vo);
//输出传入的数组
if (ids != null && ids.length > 0) {
for (Integer id : ids) {
System.out.println("传入的商品列表分别为:" + id);
}
}
return "itemList";
}
-
- List类型的绑定
基于批量修改商品操作完成参数传递。
Jsp修改
控制器修改
POJO修改
- @RequestMapping注解的使用
- 路径映射可以是数组
-
- @RequestMapping可以加在类头部,用于目录分级管理
-
- 限定请求方法
- Controller方法返回值
- 返回ModelAndView
参考第一天内容。
-
- 返回void
- request
- 返回void
新建msg.jsp
-
-
- response
-
-
- 返回String
- 返回视图名字,参考第一天内容
- 返回String
-
-
- redirect与forward
-
- Springmvc中异常处理
思想:做一个全局异常处理器,处理所有没有处理过的运行时异常用于更友好地提示用户。
-
- 步骤
- 创建全局异常处理器
- 步骤
/**
* 全局异常处理器
* @author Steven
*
*/
public class CustomerException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object hanlder,
Exception e) {
//记录日志
e.printStackTrace();
//错误消息
String msg = "很抱歉,系统发生异常了,请联系管理员";
//响应用户错误提示
ModelAndView mav = new ModelAndView();
//返回错误消息
mav.addObject("msg", msg);
//响应错误提示页面
mav.setViewName("msg");
return mav;
}
}
-
-
- 配置异常处理器
-
-
-
- 测试访问queryVoid.action
-
-
-
- 更智能、更友好的提示,解决方案
- 新建自定义异常类
- 更智能、更友好的提示,解决方案
-
/**
* 自定义异常
* @author Steven
*
*/
public class MyException extends Exception {
//错误消息
private String msg;
public MyException() {
super();
}
public MyException(String msg) {
super();
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
-
-
-
- 修改异常处理器,加上异常判断
-
-
-
-
-
- 测试访问queryVoid.action
-
-
- 图片上传处理
- 配置虚拟目录
-
- 加入上传功能需要的jar包
-
- 配置多媒体解析器
<!-- 配置多媒体处理器 -->
<!-- 注意:这里id必须填写:multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 最大上传文件大小 -->
<property name="maxUploadSize" value="8388608" />
</bean>
-
- jsp修改
-
- 编写图片上传处理代码
//图片上传用MultipartFile接收文件
@RequestMapping(value = "updateItem", method = { RequestMethod.POST, RequestMethod.GET })
public String updateItem(Item item, Model model, MultipartFile picFile) throws Exception {
// 图片新名字
String name = UUID.randomUUID().toString();
// 图片原名字
String oldName = picFile.getOriginalFilename();
// 后缀名
String exeName = oldName.substring(oldName.lastIndexOf("."));
File pic = new File("D:\\WebWork\\" + name + exeName);
// 保存图片到本地磁盘
picFile.transferTo(pic);
// 更新商品图片信息
item.setPic(name + exeName);
itemServices.update(item);
model.addAttribute("item", item);
model.addAttribute("msg", "修改商品成功");
return "itemEdit";
}
- json数据交互
- 加入jar包
-
- 编码
/**
* json数据交互演示
*
* @param item2
* @return
*/
@RequestMapping("getItem")
//@ResponseBody把pojo转成json串响应用户
@ResponseBody
//@RequestBody用于接收用户传入json串转成pojo
public Item getItem(@RequestBody Item item2) {
System.out.println("接收到的json商品数据为:" + item2);
Item item = itemServices.getItemById(3);
return item;
}
-
- 测试,安装google浏览器测试工具
详情可查看教案上的安装谷歌浏览器工具节点
- Springmvc实现Restful
- 编码
/**
* RESTful风格演示
*
* @param ids
* @param model
* @return
*/
//RESTful风格url上的参数通过{}点位符绑定
//点位符参数名与方法参数名不一致时,通过@PathVariable绑定
@RequestMapping("/item/{id}")
public String testRest(@PathVariable("id") Integer ids, Model model) {
Item item = itemServices.getItemById(ids);
model.addAttribute("item", item);
return "itemEdit";
}
-
- 测试
测试直接访问url{http://localhost:8080/项目名/item/1.action}即可。
- 拦截器
- 拦截器开发流程
- 创建拦截器
- 一号拦截器
- 创建拦截器
- 拦截器开发流程
/**
* 自定义拦截器
* @author Steven
*
*/
public class MyInterceptor1 implements HandlerInterceptor {
//在Controller方法执行后被执行
//处理异常、记录日志
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("MyInterceptor1.afterCompletion.....");
}
//在Controller方法执行后,返回ModelAndView之前被执行
//设置或者清理页面共用参数等等
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("MyInterceptor1.postHandle.....");
}
//在Controller方法执行前被执行
//登录拦截、权限认证等等
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("MyInterceptor1.preHandle.....");
//返回true放行,false拦截
return true;
}
}
-
-
-
- 二号拦截器,复制一号,修改一下系统输出消息
-
-
-
-
- 配置拦截器
-
<!-- 拦截器定义 -->
<mvc:interceptors>
<!-- 定义一个拦截器 -->
<mvc:interceptor>
<!-- path配置</**>拦截所有请求,包括二级以上目录,</*>拦截所有请求,不包括二级以上目录 -->
<mvc:mapping path="/**"/>
<bean class="com.itheima.springmvc.interceptor.MyInterceptor1" />
</mvc:interceptor>
<!-- 定义一个拦截器 -->
<mvc:interceptor>
<!-- path配置</**>拦截所有请求,包括二级以上目录,</*>拦截所有请求,不包括二级以上目录 -->
<mvc:mapping path="/**"/>
<bean class="com.itheima.springmvc.interceptor.MyInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
-
-
- 测试流程,可参考教案
-
-
- 拦截器案例应用,登录拦截器
- 思路
- 拦截器案例应用,登录拦截器
- 有一个登录页面,需要写一个controller访问页面
- 登录页面有一提交表单的动作。需要在controller中处理。
- 判断用户名密码是否正确
- 如果正确 想session中写入用户信息
- 返回登录成功,或者跳转到商品列表
- 拦截器。
- 拦截用户请求,判断用户是否登录
- 如果用户已经登录。放行
- 如果用户未登录,跳转到登录页面。
-
-
- login.jsp
-
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用户登录</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/user/login.action">
用户名:<input type="text" name="username" /><br>
密码:<input type="password" name="password" /><br>
<input type="submit">
</form>
</body>
</html>
-
-
- UserController
-
/**
* 登录拦截器
* @author Steven
*
*/
@Controller
@RequestMapping("user")
public class UserController {
/**
* 跳转登录页面
* @return
*/
@RequestMapping("toLogin")
public String toLogin(){
return "login";
}
/**
* 用户登录
* @return
*/
@RequestMapping("login")
public String login(String username,String password,HttpSession session){
String result = "login";
//断定用户是否允许登录
if(username != null){
session.setAttribute("username", username);
//登录成功,跳转商品列表
result = "redirect:/itemList.action";
}
return result;
}
}
-
-
- LoginInterceptor拦截器编码
-
这里省略类声名和其它两个方法。
//处理执行前被执行
//登录拦截、权限验证
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
Object attribute = request.getSession().getAttribute("username");
if(attribute != null){
//放行,执行处理器
return true;
}else{
response.sendRedirect(request.getContextPath() + "/user/tologin.action");
//放行,执行处理器
return false;
}
}
-
-
- 拦截器配置
-
<!-- 登录拦截器 -->
<mvc:interceptor>
<!-- path配置</**>拦截所有请求,包括二级以上目录,</*>拦截所有请求,不包括二级以上目录 -->
<mvc:mapping path="/**"/>
<!-- 配置不拦截请求的地址 -->
<!-- <mvc:exclude-mapping path="/user/toLogin.action"/>
<mvc:exclude-mapping path="/user/login.action"/> -->
<mvc:exclude-mapping path="/user/*"/>
<bean class="com.itheima.springmvc.interceptor.LoginInterceptor" />
</mvc:interceptor>