软件开发中的MVC设计模式

  软件开发的目标是减小耦合,让模块之前关系清晰.

  MVC模式在软件开发中经常和ORM模式一起应用,主要作用是将(数据抽象,数据实体传输和前台数据展示)分层,这样前台,后台,数据库三层分离,减小耦合.

  

  1)Model  :  负责抽象并存储数据库数据

  2)Controller :  负责数据的转化和传输

  3)View    :  负责展示数据

  注意 框架的应用使软件开发变得更有章可循,更规范化,软件开发的每个职责都落到了具体的模块中去

      ORM框架 : 将数据库数据封装存储至Model类中

      MVC框架 : 前台数据与实体数据的互为转化

      开发者   : 配置框架,编写业务代码,前台数据展示页面

SpringMVC工作流

  SpringMVC是建立在Spring framework之上的一个MVC框架,主要的组件有前端控制器处理器映射器处理器适配器视图解析器.

   

  1.SpringMVC的原理就如上图所展示的,客户端发来HTTP请求,

  2.前端控制器作为一个顶层执行者获取请求,

  3.返回一个执行链HandlerExecutionChain{HandlerInterceptor1,HandlerInterceptor2,Handler},

  4.前端控制器请求映射器查询对应的处理器适配器,

  5.处理器适配器代理执行处理器,

  6.处理器响应处理,返回一个ModelAndView,

  7.适配器返回一个ModelAndView至前端控制器

  8.前端控制器请求视图解析器执行解析,

  9.解析器返回一个未经渲染的视图

  10.前端控制器渲染视图,将模型数据存于request域

  11.视图发至浏览器进行渲染呈现

  注意,上图分为Model,View,Controller等模块,其中Model里面可封装许多逻辑,这一部分未在步骤上进行说明.

对比Struts2

  1.SpringMVC的前端入口是一个名为DispatchServlet的servlet,Struts2是一个Filter过滤器;

  2.SpringMVC基于方法进行开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或者多例模式,Struts2是基于类开发,传递的参数通过类的属性进行传递;

  3.Struts2采用值栈存储请求和响应,通过OGNL存取数据,SpringMVC通过参数解析器将request内容进行解析,并给方法形参赋值,将数据和视图封装成一个ModelAndView对象,最后将ModelAndView的数据传入request中以及视图渲染,JSP使用JSTL来进行取值操作;

组件职责描述

1.前端控制器DispatcherServlet(无需开发者开发)

作用 : 接收请求,响应结果,相当于转发器,中央处理器.

  有了DispatcherServlet减少了其它组件之间的耦合度.

类位置  org.springframework.web.servlet.DispatcherServlet.class

配置文件  /org/springframework/web/servlet/DispatcherServlet.properties

<servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>

配置方式

2.处理器映射器HandlerMapping(无需开发者开发)

    作用:根据请求的url查找Handler和Interceptor拦截器,

      将它们封装在HandlerExecutionChain 对象中给前端控制器返回.

类位置  org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping.class

<!—beanName Url映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

配置方式

        org.springframework.web.servlet.handler.SimpleUrlHandlerMapping.class

<!—

简单url映射
simpleUrlHandlerMapping是BeanNameUrlHandlerMapping的增强版本,它可以将url和处理器bean的id进行统一映射配置
-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/items1.action">controller的bean id</prop>
<prop key="/items2.action">controller的bean id</prop>
</props>
</property>
</bean>

配置方式

     org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.class

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

配置方式

3.处理器适配器HandlerAdapter(无需开发者开发)

作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler

    类位置  org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.class

<!--
所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean通过此适配器进行适配、执行.
--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

配置方式

         org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.class

<!--
所有实现了org.springframework.web.HttpRequestHandler 接口的Bean通过此适配器进行适配、执行.
--> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>

配置方式

         org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.class

<!--
注解时使用的Adapter,配合注解映射器一起使用
--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

配置方式

4.处理器Handler(需开发者开发)

注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler

    非注解方式

package com.harry.controller;

import java.util.ArrayList;
import java.util.List; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller; import com.harry.entity.Items; /***
* @author harry
* 用于处理页面请求,
* 数据来源是通过数据库ORM映射至实体类来获取,
* 这里使用静态获取数据进行简单演示.
*/
public class ItemList_1 implements Controller { @Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception { //调用service查找 数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据 Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!"); Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!"); itemsList.add(items_1);
itemsList.add(items_2); //返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当 于request的setAttribut,在jsp页面中通过itemsList取数据
modelAndView.addObject("itemsList", itemsList); //指定视图
modelAndView.setViewName("Items/itemList"); return modelAndView;
} }

ItemList_1.java

    注解方式

@Controller
public class ItemList_2 {
/*
RequestMappingHandlerMapping将对类中标记@ResquestMapping的方法进行映射,根据ResquestMapping定义的url匹配ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器,HandlerMethod对象中封装url对应的方法Method
*/
@RequestMapping("/queryItem.action")
public ModelAndView queryItem() {
// 商品列表
List<Items> itemsList = new ArrayList<Items>(); Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!"); Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!"); itemsList.add(items_1);
itemsList.add(items_2); // 创建modelAndView准备填充数据、设置视图
ModelAndView modelAndView = new ModelAndView(); // 填充数据
modelAndView.addObject("itemsList", itemsList);
// 视图
modelAndView.setViewName("order/itemsList"); return modelAndView;
} }

ItemList_2.java

注意,注解方式应使用注解包扫描<context:component-scan base-package="com.harry.controller"/>,

包扫描可以扫描到@Bean,@Controller,@Service,@Repository等注解类.

RequestMappingHandlerMapping,HttpRequestHandlerAdapter(<mvc:annotation-driven>可自动加载这两个类)

5.视图解析器View resolver(无需开发者开发)

作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)

类位置  org.springframework.web.servlet.view.InternalResourceViewResolver.class

<!-- ViewResolver配置 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

配置方式

6.视图View(需开发者开发)

View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...) 

案例驱动开发

  springmvc的开发,需要配置上述工作流中的组件,入门程序紧接着框架应用:Mybatis - 开发详述的案例进行开发,

  1.备份数据库,实体类

-- MySQL dump 10.13  Distrib 5.7.18, for Linux (x86_64)
--
-- Host: localhost Database: mybatis
-- ------------------------------------------------------
-- Server version 5.7.18-0ubuntu0.16.04.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; --
-- Table structure for table `items`
-- DROP TABLE IF EXISTS `items`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '商品名称',
`price` float(10,1) NOT NULL COMMENT '商品定价',
`detail` text COMMENT '商品描述',
`pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
`createtime` datetime NOT NULL COMMENT '生产日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; --
-- Dumping data for table `items`
-- LOCK TABLES `items` WRITE;
/*!40000 ALTER TABLE `items` DISABLE KEYS */;
INSERT INTO `items` VALUES (1,'台式机',3000.0,'该电脑质量非常好!!!!',NULL,'2015-02-03 13:22:53'),(2,'笔记本',6000.0,'笔记本性能好,质量好!!!!!',NULL,'2015-02-09 13:22:57'),(3,'背包',200.0,'名牌背包,容量大质量好!!!!',NULL,'2015-02-06 13:23:02');
/*!40000 ALTER TABLE `items` ENABLE KEYS */;
UNLOCK TABLES; --
-- Table structure for table `orderdetail`
-- DROP TABLE IF EXISTS `orderdetail`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `orderdetail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orders_id` int(11) NOT NULL COMMENT '订单id',
`items_id` int(11) NOT NULL COMMENT '商品id',
`items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',
PRIMARY KEY (`id`),
KEY `FK_orderdetail_1` (`orders_id`),
KEY `FK_orderdetail_2` (`items_id`),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; --
-- Dumping data for table `orderdetail`
-- LOCK TABLES `orderdetail` WRITE;
/*!40000 ALTER TABLE `orderdetail` DISABLE KEYS */;
INSERT INTO `orderdetail` VALUES (1,3,1,1),(2,3,2,3),(3,4,3,4),(4,4,2,3);
/*!40000 ALTER TABLE `orderdetail` ENABLE KEYS */;
UNLOCK TABLES; --
-- Table structure for table `orders`
-- DROP TABLE IF EXISTS `orders`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下单用户id',
`number` varchar(32) NOT NULL COMMENT '订单号',
`createtime` datetime NOT NULL COMMENT '创建订单时间',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; --
-- Dumping data for table `orders`
-- LOCK TABLES `orders` WRITE;
/*!40000 ALTER TABLE `orders` DISABLE KEYS */;
INSERT INTO `orders` VALUES (3,1,'','2015-02-04 13:22:35',NULL),(4,1,'','2015-02-03 13:22:41',NULL),(5,10,'','2015-02-12 16:13:23',NULL);
/*!40000 ALTER TABLE `orders` ENABLE KEYS */;
UNLOCK TABLES; --
-- Table structure for table `user`
-- DROP TABLE IF EXISTS `user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; --
-- Dumping data for table `user`
-- LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,'王五',NULL,'',NULL),(10,'张三','2014-07-10','','北京市'),(16,'张小明',NULL,'','河南郑州'),(22,'陈小明',NULL,'','河南郑州'),(24,'张三丰',NULL,'','河南郑州'),(25,'陈小明',NULL,'','河南郑州'),(26,'王五',NULL,NULL,NULL);
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2017-10-10 0:00:04

sql

package com.harry.entity;

import java.util.Date;

public class Items {
private Integer id; private String name; private Float price; private String pic; private Date createtime; private String detail; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name == null ? null : name.trim();
} public Float getPrice() {
return price;
} public void setPrice(Float price) {
this.price = price;
} public String getPic() {
return pic;
} public void setPic(String pic) {
this.pic = pic == null ? null : pic.trim();
} public Date getCreatetime() {
return createtime;
} public void setCreatetime(Date createtime) {
this.createtime = createtime;
} public String getDetail() {
return detail;
} public void setDetail(String detail) {
this.detail = detail == null ? null : detail.trim();
}
}

Items.java

package com.harry.entity;

import java.util.Date;
import java.util.List; public class Orders {
private Integer id; private Integer userId; private String number; private Date createtime; private String note; //用户信息
private User user; //订单明细
private List<Orderdetail> orderdetails; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public Integer getUserId() {
return userId;
} public void setUserId(Integer userId) {
this.userId = userId;
} public String getNumber() {
return number;
} public void setNumber(String number) {
this.number = number == null ? null : number.trim();
} public Date getCreatetime() {
return createtime;
} public void setCreatetime(Date createtime) {
this.createtime = createtime;
} public String getNote() {
return note;
} public void setNote(String note) {
this.note = note == null ? null : note.trim();
} public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
} public List<Orderdetail> getOrderdetails() {
return orderdetails;
} public void setOrderdetails(List<Orderdetail> orderdetails) {
this.orderdetails = orderdetails;
} @Override
public String toString() {
return "Orders [id=" + id + ", userId=" + userId + ", number=" + number + ", createtime=" + createtime
+ ", note=" + note + ", user=" + user + ", orderdetails=" + orderdetails + "]";
} }

Orders.java

package com.harry.entity;

public class Orderdetail {
private Integer id; private Integer ordersId; private Integer itemsId; private Integer itemsNum; //明细对应的商品信息
private Items items; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public Integer getOrdersId() {
return ordersId;
} public void setOrdersId(Integer ordersId) {
this.ordersId = ordersId;
} public Integer getItemsId() {
return itemsId;
} public void setItemsId(Integer itemsId) {
this.itemsId = itemsId;
} public Integer getItemsNum() {
return itemsNum;
} public void setItemsNum(Integer itemsNum) {
this.itemsNum = itemsNum;
} public Items getItems() {
return items;
} public void setItems(Items items) {
this.items = items;
} @Override
public String toString() {
return "Orderdetail [id=" + id + ", ordersId=" + ordersId
+ ", itemsId=" + itemsId + ", itemsNum=" + itemsNum + "]";
} }

Orderdetail.java

package com.harry.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.List; @SuppressWarnings("serial")
public class User implements Serializable { //属性名和数据库表的字段对应
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址 //用户创建的订单列表
private List<Orders> ordersList;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex
+ ", birthday=" + birthday + ", address=" + address + "]";
}
public List<Orders> getOrdersList() {
return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
this.ordersList = ordersList;
} }

User.java

  2.导入spring ioc, aop, mvc, log4j...的jar包,这里使用maven 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/jdbc/spring-cache.xsd
">
<modelVersion>4.0.0</modelVersion>
<groupId>com.harry</groupId>
<artifactId>harry-ssm</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>harry-ssm Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.11.RELEASE</version>
</dependency> <!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency> <!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency> </dependencies>
<build>
<finalName>harry-ssm</finalName>
</build>
</project>

pom.xml  

  3.配置前端控制器,springmvc的入口组件

<!--
contextConfigLocation指定springmvc的主配置文件地址,如不指定则默认为WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml <load-on-startup>1</load-on-startup> 服务器启动时创建 <url-pattern>*.action</url-pattern> 拦截地址指明所有.action结尾的地址
--> <servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>

web.xml

  4.配置处理器适配器

<!--
配置处理器适配器:简单处理器适配器
所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为Springmvc的后端控制器。
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

springmvc.xml

  5.配置处理器

package com.harry.controller;

import java.util.ArrayList;
import java.util.List; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller; import com.harry.entity.Items; /***
* @author harry
* 用于处理页面请求,
* 数据来源是通过数据库ORM映射至实体类来获取,
* 这里使用静态获取数据进行简单演示.
*/
public class ItemList_1 implements Controller { @Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception { //调用service查找 数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据 Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!"); Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!"); itemsList.add(items_1);
itemsList.add(items_2); //返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当 于request的setAttribut,在jsp页面中通过itemsList取数据
modelAndView.addObject("itemsList", itemsList); //指定视图
modelAndView.setViewName("Items/itemList"); return modelAndView;
} }

ItemList_1.java

<!-- controller配置 -->
<bean name="/items1.action" id="itemList1"
class="cn.itcast.springmvc.controller.first.ItemList1"/>

springmvc.xml

  6.配置处理器映射器

<!-- 处理器映射器 -->
<!-- 根据bean的name进行查找Handler 将action的url配置在bean的name中 -->
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

springmvc.xml

  7.配置视图解析器

<!--
ViewResolver配置
JstlView 指视图使用jstl类库支持
prefix,前缀
suffix,后缀
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

springmvc.xml

  8.编写视图

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page isELIgnored ="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!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>
商品列表:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td>商品价格</td>
<td>商品描述</td>
</tr>
<c:forEach items="${itemsList }" var="item">
<tr>
<td>${item.name}</td>
<td>${item.price}</td>
<td>${item.detail}</td>
</tr>
</c:forEach> </table>
</body>
</html>

itemList.jsp

  9.访问http://localhost:8080/harry-ssm/items1.action

    

源码工作流

  描述的工作流与上面画的图一致,只不过这次使用源码来进行流程分析.

  1.读取context中的配置,初始化各大组件

  

  2.客户端发来请求,DispatchServlet接收请求,触发doService方法,doService方法调用doDispatch方法

  

  

  3.doDispatch调用getHandler获取Handler,调用getHandlerAdapter获取Adapter

  

  

  4.getHandler通过HandlerMapping对象返回HandlerExecutionChain

  

  5.从HandlerExecutionChain中获取Handler并交由HandlerAdapter执行

  

  6.获取的ModelAndView对象,调用render方法渲染  

  

  7.render方法通过调用视图解析器来获取视图

  

  

  8.DispatchServlet渲染视图,将Model数据放在request域中

  

  9.客户端读取响应

整合SSM

  Spring整合Mybatis这个ORM框架已经在 框架应用:Mybatis  - 开发详述 整合过了,现在三个框架进行整合.

  需要完成的工作其实就是处理这关系线:

    User <--> View <--> Action <--> Service <--> DAO <--> DB

                ---------------------Spring-------------------

  DAO层连接数据库需要要数据源信息db.properties,框架需要log4j.properties,mybatis的总配置文件sqlMapConfig.xml,使用spring来配置数据源,管理事务,配置SqlSessionFactory和mapper扫描器的applicationContext-dao.xml,Mapper对象的配置文件XXXMapper.xml.

  Service层用spring配置service接口applicationContext-service.xml,配置事务管理applicationContext-transaction.xml,Service接口 

  Action层springmvc配置文件springmvc.xml,web.xml中配置DispatchServlet,配置编码转换器,加载spring容器,Controller类

    

    DAO

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=XXXX
jdbc.password=XXXX

db.properties

# Global logging configuration,建议开发环境中要用debug
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

log4j.properties

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration> <!—使用自动扫描器时,mapper.xml文件如果和mapper.java接口在一个目录则此处不用定义mappers -->
<mappers>
<package name="com.harry.ssm.mapper" />
</mappers>
</configuration>

sqlMapConfig.xml

<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:property-placeholder location="classpath:db.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="30"/>
<property name="maxIdle" value="5"/>
</bean> <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
</bean>
<!-- mapper扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.harry.ssm.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean> </beans>

applicationContext-dao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.harry.ssm.mapper.ItemsMapper"> <!-- sql片段 -->
<!-- 商品查询条件 -->
<sql id="query_items_where">
<if test="items!=null">
<if test="items.name!=null and items.name!=''">
and items.name like '%${items.name}%'
</if>
</if>
</sql> <!-- 查询商品信息 -->
<select id="findItemsList" parameterType="queryVo" resultType="items">
select * from items
<where>
<include refid="query_items_where"/>
</where>
</select> </mapper>

ItemsMapper.xml

public interface ItemsMapper {
//商品列表
public List<Items> findItemsList(QueryVo queryVo) throws Exception;
}

ItemsMapper.java

    Service

<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 ">
<!-- 商品管理的service -->
<bean id="itemsService" class="com.harry.ssm.service.impl.ItemsServiceImpl"/>
</beans>

applicationContext-service.xml

<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 "> <!-- 事务管理器
对mybatis操作数据库事务控制,spring使用jdbc的事务控制类
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源
dataSource在applicationContext-dao.xml中配置了
-->
<property name="dataSource" ref="dataSource"/>
</bean> <!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- aop -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.harry.ssm.service.impl.*.*(..))"/>
</aop:config> </beans>

applicationContext-transaction.xml

package com.harry.ssm.service;

import java.util.List;

import com.harryt.ssm.po.ItemsCustom;
import com.harry.ssm.po.ItemsQueryVo; public interface ItemsService { //商品查询列表
public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception; //根据id查询商品信息
/**
*
* <p>Title: findItemsById</p>
* <p>Description: </p>
* @param id 查询商品的id
* @return
* @throws Exception
*/
public ItemsCustom findItemsById(Integer id) throws Exception; //修改商品信息
/**
*
* <p>Title: updateItems</p>
* <p>Description: </p>
* @param id 修改商品的id
* @param itemsCustom 修改的商品信息
* @throws Exception
*/
public void updateItems(Integer id,ItemsCustom itemsCustom) throws Exception; }

IItemsService.java

package com.harry.ssm.service.impl;

import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import com.harry.ssm.mapper.ItemsMapper;
import com.harry.ssm.mapper.ItemsMapperCustom;
import com.harry.ssm.po.Items;
import com.harry.ssm.po.ItemsCustom;
import com.harry.ssm.po.ItemsQueryVo;
import com.harry.ssm.service.ItemsService; public class ItemsServiceImpl implements ItemsService{ @Autowired
private ItemsMapperCustom itemsMapperCustom; @Autowired
private ItemsMapper itemsMapper; @Override
public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo)
throws Exception {
//通过ItemsMapperCustom查询数据库
return itemsMapperCustom.findItemsList(itemsQueryVo);
} @Override
public ItemsCustom findItemsById(Integer id) throws Exception { Items items = itemsMapper.selectByPrimaryKey(id);
//中间对商品信息进行业务处理
//....
//返回ItemsCustom
ItemsCustom itemsCustom = new ItemsCustom();
//将items的属性值拷贝到itemsCustom
BeanUtils.copyProperties(items, itemsCustom); return itemsCustom; } @Override
public void updateItems(Integer id, ItemsCustom itemsCustom) throws Exception {
//添加业务校验,通常在service接口对关键参数进行校验
//校验 id是否为空,如果为空抛出异常 //更新商品信息使用updateByPrimaryKeyWithBLOBs根据id更新items表中所有字段,包括 大文本类型字段
//updateByPrimaryKeyWithBLOBs要求必须转入id
itemsCustom.setId(id);
itemsMapper.updateByPrimaryKeyWithBLOBs(itemsCustom);
} }

ItemsServiceImpl.java

    Action

<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 "> <!-- 扫描controller注解,多个包中间使用半角逗号分隔 -->
<context:component-scan base-package="com.harry.ssm.controller"/> <!--注解映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- ViewResolver -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean> </beans>

springmvc.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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
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</display-name> <!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring/applicationContext.xml,/WEB-INF/classes/spring/applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <!-- 解决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> <!-- springmvc的前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</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>

web.xml

package com.harry.ssm.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView; import com.harry.ssm.po.ItemsCustom;
import com.harry.ssm.service.ItemsService; @Controller
//为了对url进行分类管理 ,可以在这里定义根路径,最终访问url是根路径+子路径
//比如:商品列表:/items/queryItems.action
@RequestMapping("/items")
public class ItemsController { @Autowired
private ItemsService itemsService; // 商品查询
@RequestMapping("/queryItems")
public ModelAndView queryItems(HttpServletRequest request) throws Exception {
//测试forward后request是否可以共享 System.out.println(request.getParameter("id")); // 调用service查找 数据库,查询商品列表
List<ItemsCustom> itemsList = itemsService.findItemsList(null); // 返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 相当 于request的setAttribut,在jsp页面中通过itemsList取数据
modelAndView.addObject("itemsList", itemsList); // 指定视图
// 下边的路径,如果在视图解析器中配置jsp路径的前缀和jsp路径的后缀,修改为
// modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
// 上边的路径配置可以不在程序中指定jsp路径的前缀和jsp路径的后缀
modelAndView.setViewName("items/itemsList"); return modelAndView; } //商品信息修改页面显示
//@RequestMapping("/editItems")
//限制http请求方法,可以post和get
// @RequestMapping(value="/editItems",method={RequestMethod.POST,RequestMethod.GET})
// public ModelAndView editItems()throws Exception {
//
// //调用service根据商品id查询商品信息
// ItemsCustom itemsCustom = itemsService.findItemsById(1);
//
// // 返回ModelAndView
// ModelAndView modelAndView = new ModelAndView();
//
// //将商品信息放到model
// modelAndView.addObject("itemsCustom", itemsCustom);
//
// //商品修改页面
// modelAndView.setViewName("items/editItems");
//
// return modelAndView;
// } @RequestMapping(value="/editItems",method={RequestMethod.POST,RequestMethod.GET})
//@RequestParam里边指定request传入参数名称和形参进行绑定。
//通过required属性指定参数是否必须要传入
//通过defaultValue可以设置默认值,如果id参数没有传入,将默认值和形参绑定。
public String editItems(Model model,@RequestParam(value="id",required=true) Integer items_id)throws Exception { //调用service根据商品id查询商品信息
ItemsCustom itemsCustom = itemsService.findItemsById(items_id); //通过形参中的model将model数据传到页面
//相当于modelAndView.addObject方法
model.addAttribute("itemsCustom", itemsCustom); return "items/editItems";
} //商品信息修改提交
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(HttpServletRequest request,Integer id,ItemsCustom itemsCustom)throws Exception { //调用service更新商品信息,页面需要将商品信息传到此方法
itemsService.updateItems(id, itemsCustom); //重定向到商品查询列表
// return "redirect:queryItems.action";
//页面转发
//return "forward:queryItems.action";
return "success";
} }

ItemsController.java

    View

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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 }/item/queryItem.action" method="post">
查询条件:
<table width="100%" border=1>
<tr>
<td><input type="submit" value="查询"/></td>
</tr>
</table>
商品列表:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td>商品价格</td>
<td>生产日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<c:forEach items="${itemsList }" var="item">
<tr>
<td>${item.name }</td>
<td>${item.price }</td>
<td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>${item.detail }</td> <td><a href="${pageContext.request.contextPath }/items/editItems.action?id=${item.id}">修改</a></td> </tr>
</c:forEach> </table>
</form>
</body> </html>

itemsList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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 id="itemForm" action="${pageContext.request.contextPath }/items/editItemsSubmit.action" method="post" >
<input type="hidden" name="id" value="${itemsCustom.id }"/>
修改商品信息:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="${itemsCustom.name }"/></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="${itemsCustom.price }"/></td>
</tr>
<tr>
<td>商品生产日期</td>
<td><input type="text" name="createtime" value="<fmt:formatDate value="${itemsCustom.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
</tr>
<%-- <tr>
<td>商品图片</td>
<td>
<c:if test="${item.pic !=null}">
<img src="/pic/${item.pic}" width=100 height=100/>
<br/>
</c:if>
<input type="file" name="pictureFile"/>
</td>
</tr> --%>
<tr>
<td>商品简介</td>
<td>
<textarea rows="3" cols="30" name="detail">${itemsCustom.detail }</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交"/>
</td>
</tr>
</table> </form>
</body> </html>

editItems.jsp

@RequestMapping

  定义于Controller类及其方法上,用于指定访问的url的文件映射路径和访问方法,如

@RequestMapping("/items")
public class ItemsController {

  @RequestMapping("/queryItems",method={RequestMethod.POST,RequestMethod.GET})
  public ModelAndView queryItems(HttpServletRequest request) throws Exception {

那么,指定的路径为http://localhost:8080/appName/items/queryitems.action,有POST和GET两种访问方式

Controller方法返回值

  ModelAndView    对象可添加model数据和指定view

  void         可以利用内部跳转进行响应,或者重定向,或者响应json数据

             request.getRequestDispatcher("页面路径").forward(request, response);

             response.sendRedirect("url")

  String        指定逻辑视图名,重定向,内部跳转

             return "item/editItem";

             return "redirect:queryItem.action";

             return "forward:editItem.action";

参数绑定

   参数绑定可以是客户端数据绑定,也可以是服务端参数绑定;

  服务端参数绑定就是在request<--controller这个过程之间发生的事,request到达controller控制权就在我们的手上,我们可以运行自己的逻辑代码,然后获取参数,然后再将其绑定在request域中,等着给DispatchServlet渲染.

  支持的类型:HttpServletRequest,HttpServletResponse,HttpSession,Model/ModelMap

Items item = itemService.findItemById(id);

model.addAttribute("item", item);

modelMap是model接口实现类,实质上都是实例化ModelMap来存储key/value

页面通过${item.xxx}来取值.

  客户端参数绑定就是request-->controller,将客户填入的数据进行自动获取至方法上

  支持的类型:基础类型(Bollean,Integer,String,Float/Double),POJO,自定义类型转换器,集合类

public String editItem(Model model,Integer id,Boolean status) throws Exception
http://localhost:8080/springmvc_mybatis/item/editItem.action?id=2&status=false

参数id和status将自动获取

@RequestParam 常用来处理基础类型

public String editItem(@RequestParam(value="item_id",required=true) String id

  @RequestParam(value="item_status",defaultValue="true") Boolean status) {}

页面定义

<input type="text" name="name"/>

<input type="text" name="price"/>

Controller方法定义,获取items匹配的属性名name,price

@RequestMapping("/editItemSubmit")

public String editItemSubmit(Items items)throws Exception{

System.out.println(items);

自定义类型转换器

public class CustomDateConverter implements Converter<String, Date> {

    @Override
public Date convert(String source) {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.parse(source);
} catch (Exception e) {
e.printStackTrace();
}
return null;
} }

CustomDateConverter.java

<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<!-- conversionService -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 转换器 -->
<property name="converters">
<list>
<bean class="com.harry.controller.converter.CustomDateConverter"/>
</list>
</property>
</bean>

springmvc.xml

  

  集合类

<input type="checkbox" name="item_id" value="001"/>
<input type="checkbox" name="item_id" value="002"/>
<input type="checkbox" name="item_id" value="003"/> -------------------------------------------------------------------------
public String deleteitem(String[] item_id)throws Exception{
System.out.println(item_id);

StringArray

<c:forEach items="${itemsList }" var="item" varStatus="s">
<tr>
<td><input type="text" name="itemsList[${s.index }].name" value="${item.name }"/></td>
<td><input type="text" name="itemsList[${s.index }].price" value="${item.price }"/></td>
.....
.....
</tr>
</c:forEach>
-----------------------------------------------------------------------------------------------------
public class QueryVo {
private List<Items> itemList;//商品列表 //get/set方法..
} -----------------------------------------------------------------------------------------------------
public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getItemList());
}

List

<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>
----------------------------------------------------------------------------------------
public class QueryVo {
private Map<String, Object> itemInfo = new HashMap<String, Object>();
//get/set方法..
}
-----------------------------------------------------------------------------------------
public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}

Map

  

自定义类与包装类

  我们在工作中一般使用逆向工程生成工具来进行代码开发,也就是ORM里面的实体部分已经是自动生成的,这部分的代码不能动,因为很容易造成代码混乱,但是我们又经常需要去修改里面的部分属性;

  我们经常还碰到另外一种情况,就是客户端请求的可能是包含几个类的视图(如多值查询),那么针对这种情况,我们可以使用一个包装类来作为视图类,然后返回视图类来进行响应,而我们上面也是这么做的.

  鉴于上述原因,我们会使用自定义类来对其进行封装,使用视图类来进行传输,这样,我们就可以在不碰那些代码的前提下任意进行代码修改.

  

  

  

  

编码问题

  相信你在开发时一定碰到过乱码问题,SpringMVC也提供了一个统一的编码过滤器,但是只适用于POST编码过滤,这是因为开发中上传表单数据都规定使用POST,所以SpringMVC也就只提供这一种过滤器.

<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>

web.xml

  还有GET的乱码解决方案有两种,

  1.修改tomcat配置文件添加编码与工程编码一致

  <Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

  2.对参数进行重新编码  

  String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8");

Validation

  数据校验一般都会在前端进行,但是有时安全性要求高点的环境下,也会在服务端进行数据校验.

  服务端校验

  Controller层  检验页面请求的合法性,在服务端控制层conroller校验,不区分客户端类型(浏览器、手机客户端、远程调用)

  Service层   不区分客户端类型(浏览器、手机客户端、远程调用)

  DAO层     一般不进行校验

  

  SpringMVC使用校验框架Validation.

  校验思路:
  页面提交请求的参数,请求到controller方法中,使用validation进行校验.如果校验出错,将错误信息展示到页面.

  1.导入Bean-Validation框架jar包,Hibernate-validator

  2.配置校验器

<!-- 校验器 -->
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!-- hibernate校验器-->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
<!-- 指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties -->
<property name="validationMessageSource" ref="messageSource" />
</bean>
<!-- 校验错误信息配置文件 -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- 资源文件名-->
<property name="basenames">
<list>
<value>classpath:CustomValidationMessages</value>
</list>
</property>
<!-- 资源文件编码格式 -->
<property name="fileEncodings" value="utf-8" />
<!-- 对资源文件内容缓存时间,单位秒 -->
<property name="cacheSeconds" value="120" />
</bean> <!--注解映射器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> -->
<!--注解适配器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> --> <!-- 使用 mvc:annotation-driven代替上边注解映射器和注解适配器配置
mvc:annotation-driven默认加载很多的参数绑定方法,
比如json转换解析器就默认加载了,如果使用mvc:annotation-driven不用配置上边的RequestMappingHandlerMapping和RequestMappingHandlerAdapter
实际开发时使用mvc:annotation-driven
-->
<mvc:annotation-driven conversion-service="conversionService"
validator="validator"></mvc:annotation-driven>

springmvc.xml

  3.在POJO中添加校验规则.

  

  4.配置校验时产生的message

  

  5.捕获校验错误信息

    

  在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收校验出错信息
  注意:@Validated和BindingResult bindingResult是配对出现,并且形参顺序是固定的(一前一后).

  6.controller传递错误信息

  

  7.页面显示错误信息

  

  8.校验分组

  在pojo中定义校验规则,而pojo是被多个 controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验.可以指定不同的分组来进行校验.

  

  9.在校验中添加分组

  

  10.在Controller指定分组的校验规则

  

数据回显

  数据回显指提交数据后出现错误,将刚才提交的数据回显到刚才的提交页面,比如填一张表,填完后一项错误后重新回到提交前的状态.

  1.SpringMVC默认对POJO进行回显.

  pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)

  

  

  2.@ModelAttribute

  @ModelAttribute可以指定POJO对应的key值,页面获取可以直接使用key值进行获取,还可以将返回值存入request域

  

  

  3.直接使用model.addAttribute

  

异常处理器

  异常处理思路很简单,就是DAO,Service,Controller出现异常直接向上抛出,然后在DispatchServlet那一层设置一个异常处理器就处理所有异常.

  

  1.创建自定义Exception  

package com.harry.exception;

@SuppressWarnings("serial")
public class ExceptionCustom extends Exception { //异常信息
public String message; public ExceptionCustom(String message){
super(message);
this.message = message;
} public String getMessage() {
return message;
} public void setMessage(String message) {
this.message = message;
}
}

ExceptionCustom.java

  2.定义全局异常处理器  

  全局异常处理器处理思路:
    解析出异常类型;
    如果该异常类型是系统自定义的异常直接取出异常信息,在错误页面展示;
    如果该异常类型不是系统自定义的异常,构造一个自定义的异常类(信息为"未知错误");

  实现SpringMVC提供的HandlerExceptionResolver接口

package com.harry.exception;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView; public class ExceptionCustomResolver implements HandlerExceptionResolver { /**
* (非 Javadoc)
* <p>Title: resolveException</p>
* <p>Description: </p>
* @param request
* @param response
* @param handler
* @param ex 系统 抛出的异常
* @return
* @see org.springframework.web.servlet.HandlerExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
*/
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
//handler就是处理器适配器要执行Handler对象(只有method) // 解析出异常类型
// 如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示
// String message = null;
// if(ex instanceof ExceptionCustom){
// message = ((ExceptionCustom)ex).getMessage();
// }else{
//// 如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
// message="未知错误";
// } //上边代码变为
ExceptionCustom ExceptionCustom = null;
if(ex instanceof ExceptionCustom){
ExceptionCustom = (ExceptionCustom)ex;
}else{
ExceptionCustom = new ExceptionCustom("未知错误");
} //错误信息
String message = ExceptionCustom.getMessage(); ModelAndView modelAndView = new ModelAndView(); //将错误信息传到页面
modelAndView.addObject("message", message); //指向错误页面
modelAndView.setViewName("error"); return modelAndView;
} }

ExceptionCustomResolver.java

  错误页面

<%@ 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>
${message }
</body>
</html>

error.jsp

  springmvc.xml配置全局异常处理器

<!-- 全局异常处理器
只要实现HandlerExceptionResolver接口就是全局异常处理器
-->
<bean class="cn.itcast.ssm.exception.CustomExceptionResolver"></bean>

springmvc.xml

上传图片

  1.当提交的表单数据混合几种数据格式,比如字符串和图片文件,必须在表单设置提交的压缩类型为multipart/form-data.

  

  2.要解析这种压缩格式的数据需要在springmvc配置文件中添加multipart类型解析器.

<!-- 文件上传 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>

springmvc.xml

  3.加上springmvc图片组件jar包

  

  4.创建图片虚拟目录存储图片

  

  或者在tomcat/conf/server.xml下

  

注意:在图片虚拟目录 中,一定将图片目录分级创建(提高i/o性能),一般我们采用按日期(年-月-日)进行分级创建.

  5.上传页面部分代码  

<tr>
<td>商品图片</td>
<td>
<c:if test="${item.pic !=null}">
<img src="/pic/${item.pic}" width=100 height=100/>
<br/>
</c:if>
<input type="file" name="pictureFile"/>
</td>
</tr>

editItems.jsp

  6.添加controller映射model,保存图片路径名称

  

  

Json数据交互

  Json数据交互的应用场景广泛,基本上每个网站都会有这样的数据交互,特点是数据交互量小,轻便,可异步刷新.

  1.json数据交互思路

  

  客户端请求json串(或者键值对) <--------> 服务端json对象

  2.springmvc采用jackson包来转换json串与json对象,所以要添加jar包

  

  3.配置json转换器

<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean> <!--如果使用<mvc:annotation-driven /> 则不用定义上边的内容 -->

springmvc.xml

  4.测试请求json串和key/value,输出json串

<%@ 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>json交互测试</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
//请求json,输出是json
function requestJson(){ $.ajax({
type:'post',
url:'${pageContext.request.contextPath }/requestJson.action',
contentType:'application/json;charset=utf-8',
//数据格式是json串,商品信息
data:'{"name":"手机","price":999}',
success:function(data){//返回json结果
alert(data);
} }); }
//请求key/value,输出是json
function requerstKeyValue(){ $.ajax({
type:'post',
url:'${pageContext.request.contextPath }/requerstKeyValue.action',
//请求是key/value这里不需要指定contentType,因为默认就 是key/value类型
//contentType:'application/json;charset=utf-8',
//数据格式是json串,商品信息
data:'name=手机&price=999',
success:function(data){//返回json结果
alert(data.name);
} }); }
</script>
</head>
<body>
<input type="button" onclick="requestJson()" value="请求json,输出是json"/>
<input type="button" onclick="requerstKeyValue()" value="请求key/value,输出是json"/>
</body>
</html>

jsonTest.jsp

package com.harry.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import com.harry.entity.ItemsCustom; @Controller
public class JsonController { //请求json串(商品信息),输出json(商品信息)
//@RequestBody将请求的商品信息的json串转成itemsCustom对象
//@ResponseBody将itemsCustom转成json输出
@RequestMapping("/requestJson")
public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom){ //@ResponseBody将itemsCustom转成json输出
return itemsCustom;
} //请求key/value,输出json
@RequestMapping("/responseJson")
public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom){ //@ResponseBody将itemsCustom转成json输出
return itemsCustom;
} }

JsonController.java

  

RESTful支持

  RESTful是一种开发理念,并非指具体的技术,理念的阐述具体如下:

  1.对url进行规范,写RESTful格式的url

  非REST的url:http://...../queryItems.action?id=001&type=T01

  REST的url风格:http://..../items/001

特点:url简洁,将参数通过url传到服务端

  2.http的方法规范

  不管是删除,添加,更新,使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加.

  后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加。

  3.对http的contentType规范

  请求时指定contentType,要json数据,设置成json格式的type.

  示例

  1.controller定义映射使用RESTful风格的url,将查询信息的id传入controller.

  

  @RequestMapping(value="/ itemsView/{id}"):{×××}占位符,请求的URL可以是“/viewItems/1”或“/viewItems/2”,通过在方法中使用@PathVariable获取{×××}中的×××变量.

   @PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上. 如果RequestMapping中表示为"/ itemsView /{id}",id和形参名称一致,@PathVariable不用指定名称.

  2.配置前端控制器

  

  "*.action"的解析在RESTful风格下会导致静态资源无法访问,这里替换成"/";

  3.springmvc.xml中配置静态资源映射

  

拦截器

拦截器能设置请求前,响应后进行拦截执行特定的代码,SpringMVC定义拦截器需要实现HandlerInterceptor接口.

接口中提供三个方法分别在handler执行前,后还有ModelAndView返回前执行

package com.harry.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; public class HandlerInterceptor1 implements HandlerInterceptor { //进入 Handler方法之前执行
//用于身份认证、身份授权
//比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception { System.out.println("HandlerInterceptor1...preHandle"); //return false表示拦截,不向下执行
//return true表示放行
return true;
} //进入Handler方法之后,返回modelAndView之前执行
//应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception { System.out.println("HandlerInterceptor1...postHandle"); } //执行Handler完成执行此方法
//应用场景:统一异常处理,统一日志处理
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception { System.out.println("HandlerInterceptor1...afterCompletion");
} }

HanlerInterceptor1.java

  针对HandlerMapping的拦截器(不推荐使用)

  完成拦截器编写后需要在HandlerMapping处进行定义,毕竟拦截器是映射阶段进行工作的.

package com.harry.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; public class HandlerInterceptor1 implements HandlerInterceptor { //进入 Handler方法之前执行
//用于身份认证、身份授权
//比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception { System.out.println("HandlerInterceptor1...preHandle"); //return false表示拦截,不向下执行
//return true表示放行
return true;
} //进入Handler方法之后,返回modelAndView之前执行
//应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception { System.out.println("HandlerInterceptor1...postHandle"); } //执行Handler完成执行此方法
//应用场景:统一异常处理,统一日志处理
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception { System.out.println("HandlerInterceptor1...afterCompletion");
} }

springmvc.xml

  全局性拦截器

<!--拦截器 -->
<mvc:interceptors>
<!--多个拦截器,顺序执行 -->
<!-- 登陆认证拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.harry.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- /**表示所有url包括子url路径 -->
<mvc:mapping path="/**"/>
<bean class="com.harry.interceptor.HandlerInterceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.harry.interceptor.HandlerInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>

springmvc.xml

  拦截器的应用 

  比如:统一日志处理拦截器,需要该 拦截器preHandle一定要放行,且将它放在拦截器链接中第一个位置.

  比如:登陆认证拦截器,放在拦截器链接中第一个位置.权限校验拦截器,放在登陆认证拦截器之后.(因为登陆通过后才校验权限)

  拦截器实现登陆认证

1.处理逻辑

  用户请求页面

  拦截器进行拦截

    如果页面无需访问权限,放行

    页面需要访问权限

      session存在校验数据,通过

      session无校验数据,转入登陆页面

 2.登陆用Controller方法和请求页面  

package com.harry.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
public class LoginController { // 登陆
@RequestMapping("/login")
public String login(HttpSession session, String username, String password)
throws Exception { // 调用service进行用户身份验证
// ... // 在session中保存用户身份信息
session.setAttribute("username", username);
// 重定向到商品列表页面
return "redirect:/items/queryItems.action";
} // 退出
@RequestMapping("/logout")
public String logout(HttpSession session) throws Exception { // 清除session
session.invalidate(); // 重定向到商品列表页面
return "redirect:/items/queryItems.action";
} }

LoginController.java

<%@ 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 }/login.action" method="post">
用户账号:<input type="text" name="username" /><br/>
用户密码 :<input type="password" name="password" /><br/>
<input type="submit" value="登陆"/>
</form>
</body>
</html>

login.jsp

   3.登陆拦截器和设置

package com.harry.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; public class LoginInterceptor implements HandlerInterceptor { //进入 Handler方法之前执行
//用于身份认证、身份授权
//比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception { //获取请求的url
String url = request.getRequestURI();
//判断url是否是公开 地址(实际使用时将公开 地址配置配置文件中)
//这里公开地址是登陆提交的地址
if(url.indexOf("login.action")>=0){
//如果进行登陆提交,放行
return true;
} //判断session
HttpSession session = request.getSession();
//从session中取出用户身份信息
String username = (String) session.getAttribute("username"); if(username != null){
//身份存在,放行
return true;
} //执行这里表示用户身份需要认证,跳转登陆页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response); //return false表示拦截,不向下执行
//return true表示放行
return false;
} //进入Handler方法之后,返回modelAndView之前执行
//应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception { System.out.println("HandlerInterceptor1...postHandle"); } //执行Handler完成执行此方法
//应用场景:统一异常处理,统一日志处理
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception { System.out.println("HandlerInterceptor1...afterCompletion");
} }

LoginInterceptor.java

        <!--拦截器 -->
<mvc:interceptors>
<!--多个拦截器,顺序执行 -->
<!-- 登陆认证拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.harry.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>

springmvc.xml




框架应用 : Spring MVC - 开发详述的更多相关文章

  1. 用Spring MVC开发简单的Web应用

    这个例子是来自于Gary Mak等人写的Spring攻略(第二版)第八章Spring @MVC中的一个例子,在此以学习为目的进行记录. 问题:想用Spring MVC开发一个简单的Web应用, 学习这 ...

  2. 用Spring MVC开发简单的Web应用程序

    1 工具与环境 借助Eclipse4.3 + Maven3.0.3构建Java Web应用程序.使用Maven内置的servlet 容器jetty,不需手工集成Web服务器到Eclipse.还帮我们自 ...

  3. 使用Spring MVC开发RESTful API

    第3章 使用Spring MVC开发RESTful API Restful简介 第一印象 左侧是传统写法,右侧是RESTful写法 用url描述资源,而不是行为 用http方法描述行为,使用http状 ...

  4. Java框架之Spring MVC(一)

    一.Spring简介 Spring MVC是当前最优秀的 MVC 框架,自从Spring 2.5 版本发布后,由于支持注解配置,易用性有了大幅度的提高.Spring 3.0 更加完善,实现了对 Str ...

  5. Spring企业级程序设计 • 【第6章 深入Spring MVC开发】

    全部章节   >>>> 本章目录 6.1 模型数据解析及控制器返回值 6.1.1 ModelAndView多种用法 6.1.2  Map添加模型数据和返回String类型值 6 ...

  6. Spring MVC开发初体验

    1.目标实现Spring MVC : Hello World! 2.工程创建步骤 new : Dynamic Web Project lib引入Spring框架libs/*.jar touch web ...

  7. 框架应用:Mybatis - 开发详述

    ORM框架 在实际开发中,工程中本质的任务是从数据库中获取数据,然后对数据进行操作,又或者写入数据.开发时语言是大多是面向对象的工程语言,这个时候就必须进行工程语言和数据库连接语言的转换,也就是所谓的 ...

  8. Java框架之Spring MVC(二)

    一.Spring MVC 验证 JSR 303 是ajvaEE6 中的一项子规范 ,叫 Bean Validation 用于对javaBean中的字段进行校验. 官方的参考实现是: Hibernate ...

  9. 二十一、MVC的WEB框架(Spring MVC)

    一.基于注解方式配置 1.首先是修改IndexContoller控制器类 1.1.在类前面加上@Controller:表示这个类是一个控制器 1.2.在方法handleRequest前面加上@Requ ...

随机推荐

  1. 九度OJ 1014 排名

    #include <iostream> #include <string.h> #include <sstream> #include <math.h> ...

  2. Java8-初识Lambda

    廉颇老矣,尚能饭否 Java,这位已经20多岁的编程语言,称得上是编程语言界的老大哥了.他曾经攻城略地,碾压各路编程语言小弟,风光无限,不可一世.现在,也是家大业大,江湖地位,很难撼动. 但是,这依然 ...

  3. 第二次项目冲刺(Beta阶段)--第三天

    一.站立式会议照片 二.项目燃尽图 三.项目进展 队员  ID 贡献比 王若凡 201421123022 20% 吕志哲 201421123021 16% 欧阳勇 201421123026 16% 卢 ...

  4. 【Alpha】——Sixth Scrum Meeting

    一.今日站立式会议照片 二.每个人的工作 成员 昨天已完成的工作 今天计划完成的工作 李永豪 对统计出现的问题进一步完善 学习将项目做成APK 郑靖涛 完善报表设计 协助设计账目一览表板块 杨海亮 测 ...

  5. 201521123113《Java程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 1.2 可选:使用常规方法总结其他上课内容. 使用NetB ...

  6. 201521123121 《JAVA程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  7. 201521123103 《Java学习笔记》 第四周学习总结

    一.本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. (1)多态性:相同形态,不同行为(不同的定义): (2)多态绑定:运行时能够自动地选择调用哪个 ...

  8. 05浏览器-02-操作DOM

    1.DOM操作梗概 本篇内容实际上在另一篇笔记<从JS和jQuery浅谈DOM操作>已经提到了重点的地方,可以戳链接另外进行阅读. 以前提到过,实际上HTML在被浏览器加载以后,会变成 & ...

  9. 深入理解分布式调度框架TBSchedule及源码分析

    简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...

  10. 【Spring源码深度解析系列 】Spring整体架构

    一.Spring的整体架构和模块 二.模块分类: 1.Core Container Core Container包含有Core .Beans.Context.和Expression  Language ...