spring MVC 框架
一, 什么是 spring MVC
Spring MVC 属于 SpringFrameWork 的后续产品, 已经融合在 Spring Web Flow 里面. Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块. 使用 Spring 可插入的 MVC 架构, 从而在使用 Spring 进行 WEB 开发时, 可以选择使用 Spring 的 SpringMVC 框架或集成其他 MVC 开发框架, 如 Struts1(现在一般不用),Struts2 等.
--------- 百度百科
从 spring 官网中可以看出, Spring MVC 原名叫 Spring Web MVC, 它是构建在 Servlet API 上的最初的 Web 框架, 从一开始就包含在 Spring 框架中. 正式名称 "Spring Web MVC" 来自其源模块 https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc 的名称, 但它通常被称为 "Spring MVC".Spring web mvc 和 Struts2 都属于表现层的框架, 它是 Spring 框架的一部分.
二, spring MVC 框架的作用
从请求中接收传入的参数, 将处理后的结果返回给页面展示
三, spring MVC 执行流程
1), 用户发送请求至前端控制器 DispatcherServlet
2), DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器.
3), 处理器映射器根据请求 url 找到具体的处理器, 生成处理器对象及处理器拦截器 (如果有则生成) 一并返回给 DispatcherServlet.
4), DispatcherServlet 通过 HandlerAdapter 处理器适配器调用处理器
5), 执行处理器(Controller, 也叫后端控制器).
6), Controller 执行完成返回 ModelAndView
7), HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet
8), DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器
9), ViewReslover 解析后返回具体 View
10) DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中).
11) DispatcherServlet 响应用户
四, 快速开发
需求: 显示商品列表
1, 导入所需基本依赖 jar 包
jar 包下载地址: springMVC_jar https://github.com/spring-projects/spring-framework
2, 在项目工程上创建源码包, 用来存放配置文件
3, 创建 spring MVC 核心配置文件, 文件名就叫 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:dubbo="http://code.alibabatech.com/schema/dubbo"
- 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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
- </beans>
4, 创建日志文件, 用于打印日志(log4j.properties)
- # Global logging configuration
- 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
5, 定义 Controller 类
ItemController 是一个普通的 java 类, 不需要实现任何接口, 只需要在类上添加 @Controller 注解即可.@RequestMapping 注解指定请求的 url, 其中 ".action" 可以加 也可以不加. 注意: 1. 这里的配置 @Controller 注解 2.@RequestMapping 用于识别域名后缀 3.modelAndView.setViewName 用于设置跳转页面
- // 在添加注解的同时, 还得配置扫描
- @Controller
- public class ItemsController {
- // 指定 url 到请求方法的映射
- //url 中输入一个地址, 例如: localhost:8888/SpringMvc/list.action
- // 用以替代了 struts 中采用的配置文件进行匹配来调用那个方法从而识别跳转那个页面
- @RequestMapping("/list")
- public ModelAndView itemsList()throws Exception{
- List<Items> itemList = new ArrayList<Items>();
- // 商品列表
- Items items_1 = new Items();
- items_1.setName("联想笔记本_3");
- 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 苹果手机!");
- itemList.add(items_1);
- itemList.add(items_2);
- // 模型视图
- //model 模型: 模型对象中存放了返回给页面的数据
- //view 视图: 视图对象中指定给返回的页面的位置
- // 创建 modelandView 对象
- ModelAndView modelAndView = new ModelAndView();
- // 添加 model(将返回给页面的数据放入模型和视图对象中)
- modelAndView.addObject("itemList", itemList);
- // 添加视图(指定给 返回页面的位置)
- modelAndView.setViewName("jsp/itemList.jsp");
- return modelAndView;
- }
- }
6, 在 SpringMvc.xml 中配置注解扫描
这里 controller 类是创建在 cn.clj.controller 包下的
- <?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:dubbo="http://code.alibabatech.com/schema/dubbo"
- 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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
- <!-- 配置 @Controller 注解扫描 -->
- <context:component-scan base-package="cn.clj.controller"/>
- </beans>
7, 在 web.xml 中配置前端控制器
注意: 指定核心配置文件名不能写错, 否则会找不到 Controller 类
- <!-- springMvc 前端控制器 -->
- <servlet>
- <servlet-name>springMvc</servlet-name>
- <!-- 路径: spring-webmvc-4.1.3.RELEASE.jar\org.springframework.web.servlet -->
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <!-- 如果没有指定 springMvc 核心配置文件那么默认会去找 / WEB_INF/+<servlet-name > 的内容 + -servlet.xml 配置文件 -->
- <!-- 指定 springMvc 核心配置文件位置 -->
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:SpringMvc.xml</param-value>
- </init-param>
- <!-- tomcat 启动时就加载这个 servlet -->
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>springMvc</servlet-name>
- <url-pattern>*.action</url-pattern>
- </servlet-mapping>
DispatcherServlet 的路径为:
8, 配置 jsp
在 WebRoot 下创建 jsp 文件夹, 用来存放 jsp
1. 需引入 jstl 标签 2. 因为传的是 itemList, 接收值不能写错
- <%@taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
- <body>
- <form action="${pageContext.request.contextPath }/search.action" method="post">
查询条件:
- <table width="100%" border=1>
- <tr>
- <!-- 如果 controller 接受的是 vo, 那么页面上 input 框中 name 属性值要等于 vo 属性. 属性 (..)进行引用 -->
- <td > 商品名称:<input type="text" name="items.name"/></td>
- <td > 商品价格:<input type="text" name="items.price"/></td>
- <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="${itemList}" 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 }/itemEdit.action?id=${item.id}">修改</a></td>
- </tr>
- </c:forEach>
- </table>
- </form>
9, 测试
此时在浏览器中输入 http://localhost:8080 / 项目名 / list.action, 如果成功跳转到显示页面为成功
二, 关于注解处理器映射器和注解处理器适配器
注解式处理器映射器: 注解式处理器映射器, 对类中标记 @ResquestMapping 的方法进行映射, 根据 ResquestMapping 定义的 url 匹配 ResquestMapping 标记的方法, 匹配成功返回 HandlerMethod 对象给前端控制器, HandlerMethod 对象中封装 url 对应的方法 Method.
注解式处理器映射器: 注解式处理器适配器, 对标记 @ResquestMapping 的方法进行适配.
方式一: 手动配置最新版本的映射器和适配器(缺点: 随着版本更新的重新配置)
- <!-- 配置最新版的注解的处理器映射器 -->
- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
- <!-- 配置最新版的注解的处理器适配器 -->
- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
方式二: 自动配置
<mvc:annotation-driven conversion-service="conversionService"></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:p="http://www.springframework.org/schema/p"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
- 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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
- <!-- 配置 @Controller 注解扫描 -->
- <context:component-scan base-package="cn.clj.controller"/>
- <!-- 如果没有显示配置处理器映射器和处理器适配器那个 springMvc 会默认的 dispatcherServlet.properties 中查找
- 对应的处理器映射器和处理器适配器去使用, 每个请求都要扫描一次的默认配置文件, 效率非常低, 会降低访问速度, 所以显示的配置处理器映射器和处理器适配器
- -->
- <!-- 注解形式的处理器适配器
- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> -->
- <!-- 注解形式的处理器映射器
- <bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"/>-->
- <!-- 配置最新版的注解的处理器映射器, 以上已经过时
- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
- <!-- 配置最新版的注解的处理器适配器
- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
- <!-- 注解驱动: 能够自动配置最新版的处理器映射器和处理器适配器 -->
- <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
- </beans>
三, 关于视图解析器
1. 分析情形
在 controller 中, 每次配置跳转页面时, 都要配置跳转视图的全部路径, 有点麻烦
2, 配置视图解析器
功能: 在配置文件中配置全局跳转视图的前缀名和后缀名, 在 controller 类只要写省去后缀的 jsp 名即可, 配置如下:
1)在 SpringMvc.xml 文件中配置视图解析器
- <!-- 配置视图解析器 -->
- <!-- 作用: 在 controller 中指定页面路径的时候就不用写页面的完整路径名称, 直接写去掉后缀的页面名 -->
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <!-- 真正页面路径 = 前缀 + 页面名称 + 后缀 -->
- <!-- 跳转视图前缀 -->
- <property name="prefix" value="/jsp/"></property>
- <!-- 跳转视图后缀 -->
- <property name="suffix" value=".jsp"></property>
- </bean>
2)更改 conroller 类中的写法
- // 添加视图(指定给 返回页面的位置)
- // modelAndView.setViewName("jsp/itemList.jsp");
- modelAndView.setViewName("itemList");
- return modelAndView;
四, SSM 整合
个人认为, SpringMvc 与 Mybatis 整合其实就是 SSM 整合, 因为 Spring 与 SpringMvc 同属于一家公司, 无需整合, 当然也需要用到 Spring 的 IOC 特性业务分配: 此时控制层交给 SpringMvc, 持久层交给 MyBatis, 创建管理交给 Spring
思路:
Dao 层:
1,SqlMapConfig.xml, 空文件即可. 需要文件头.
2,applicationContext-dao.xml.
a) 数据库连接池
b) SqlSessionFactory 对象, 需要 spring 和 mybatis 整合包下的.
c) 配置 mapper 文件扫描器.
Service 层:
,applicationContext-service.xml 包扫描器, 扫描 @service 注解的类.
,applicationContext-trans.xml 配置事务.
表现层:
Springmvc.xml
1, 包扫描器, 扫描 @Controller 注解的类.
2, 配置注解驱动.
3, 视图解析器
Web.xml
配置前端控制器.
1, 快速部署环境
1)导入相应的依赖 jar 包
此包含 Mybatis 依赖 jar 包与逆向工程依赖 jar 包, Spring 依赖 jar 包与 Spring-mybatis 整合包, SpringMVc 依赖包, 数据库驱动包, 第三方连接池
2)在工程项目下 (非 src) 创建源码包, 用来存放配置文件, 包名为 config
3)创建分层包, 采用 MVC 模式开发, 每个包的业务不同
4)创建 db.properties
- jdbc.driver=com.mysql.jdbc.Driver
- jdbc.url=jdbc:mysql://192.168.174.132:3306/SSM
- jdbc.username=root
- jdbc.password=root
5)配置 log4j.properties
- # Global logging configuration
- 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
6)创建 spring 核心配置文件之 applicationContext-dao.xml
此文件用来管理 dao 层业务: 配置数据源, 配置 SqlSessionFactory 与 dao 层 mapper 扫描
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.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="10"/>
- <property name="maxIdle" value="5"/>
- </bean>
- <!-- mapper 配置 -->
- <!-- 让 spring 管理 sqlsessionfactory 使用 mybatis 和 spring 整合包中的 -->
- <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
- <!-- 数据库连接池 -->
- <property name="dataSource" ref="dataSource"/>
- <!-- 加载 mybatis 的全局配置文件 -->
- <property name="configLocation" value="classpath:SqlMapConfig.xml"/>
- </bean>
- <!-- 配置 Mapper 扫描器 -->
- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <property name="basePackage" value="cn.clj.dao"/>
- </bean>
- </beans>
7)创建 spring 核心配置文件之 applicationContext-service.xml
此文件主要是负责业务层: 开启 service 注解扫描
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-4.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
- http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util-4.0.xsd">
- <!-- @service 扫描 -->
- <context:component-scan base-package="cn.clj.service"></context:component-scan>
- </beans>
8)创建 spring 核心配置文件之 applicationContext-transaction.xml
此文件主要负责事务: 配置事务管理并注入数据源, 配置事务通知与切面
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
- xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
- <!-- 事务管理器 -->
- <bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <!-- 数据源 -->
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 通知 -->
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <!-- 传播行为 -->
- <tx:method name="save*" propagation="REQUIRED" />
- <tx:method name="insert*" propagation="REQUIRED" />
- <tx:method name="delete*" 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:attributes>
- </tx:advice>
- <!-- 切面 -->
- <aop:config>
- <aop:advisor advice-ref="txAdvice"
- pointcut="execution(* cn.clj.service.*.*(..))" />
- </aop:config>
- </beans>
9)创建 SpringMvc 核心配置文件之 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:dubbo="http://code.alibabatech.com/schema/dubbo"
- 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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
- <!-- 配置 @Controller 注解扫描 -->
- <context:component-scan base-package="cn.clj.controller"/>
- <!-- 注解驱动: 能够自动配置最新版的处理器映射器和处理器适配器 -->
- <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
- <!-- 配置视图解析器 -->
- <!-- 作用: 在 controller 中指定页面路径的时候就不用写页面的完整路径名称, 直接写去掉后缀的页面名 -->
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <!-- 真正页面路径 = 前缀 + 页面名称 + 后缀 -->
- <!-- 跳转视图前缀 -->
- <property name="prefix" value="/jsp/"></property>
- <!-- 跳转视图后缀 -->
- <property name="suffix" value=".jsp"></property>
- </bean>
- </beans>
10)配置服务器启动扫描
整合后以上的配置文件, 服务器不能自动识别加载, 需要在 web.xml 文件中开启包扫描
- <!-- 开启 spring 各核心配置文件扫描 -->
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:applicationContext-*.xml</param-value>
- </context-param>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <!-- 开启 SpringMVc 拦截器 -->
- <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>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>SpringMvc</servlet-name>
- <url-pattern>*.action</url-pattern>
- </servlet-mapping>
以上整合环境部署大致完成
2, 整合开发
需求 1: 从数据库查询到商品信息, 并将数据返回到 jsp 中
1)开启逆向工程自动生成 pojo 类和 mapper 接口和映射文件
1.1: 导入逆向工程 jar 包 mybatis-generator-core-1.3.2
1.2 : 在 config 包下创建 generatorConfig.xml 文件
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE generatorConfiguration
- PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
- "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
- <generatorConfiguration>
- <context id="testTables" targetRuntime="MyBatis3">
- <commentGenerator>
- <!-- 是否去除自动生成的注释 true: 是 : false: 否 -->
- <property name="suppressAllComments" value="true" />
- </commentGenerator>
- <!-- 数据库连接的信息: 驱动类, 连接地址, 用户名, 密码 -->
- <jdbcConnection driverClass="com.mysql.jdbc.Driver"
- connectionURL="jdbc:mysql://192.168.174.132:3306/SSM" userId="root"
- password="root">
- </jdbcConnection>
- <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
- connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
- userId="yycg"
- password="yycg">
- </jdbcConnection> -->
- <!-- 默认 false, 把 JDBC DECIMAL 和 NUMERIC 类型解析为 Integer, 为 true 时把 JDBC DECIMAL 和
- NUMERIC 类型解析为 java.math.BigDecimal -->
- <javaTypeResolver>
- <property name="forceBigDecimals" value="false" />
- </javaTypeResolver>
- <!-- targetProject: 生成 PO 类的位置 -->
- <javaModelGenerator targetPackage="cn.clj.pojo"
- targetProject=".\src">
- <!-- enableSubPackages: 是否让 schema 作为包的后缀 -->
- <property name="enableSubPackages" value="false" />
- <!-- 从数据库返回的值被清理前后的空格 -->
- <property name="trimStrings" value="true" />
- </javaModelGenerator>
- <!-- targetProject:mapper 映射文件生成的位置 -->
- <sqlMapGenerator targetPackage="cn.clj.dao"
- targetProject=".\src">
- <!-- enableSubPackages: 是否让 schema 作为包的后缀 -->
- <property name="enableSubPackages" value="false" />
- </sqlMapGenerator>
- <!-- targetPackage:mapper 接口生成的位置 -->
- <javaClientGenerator type="XMLMAPPER"
- targetPackage="cn.clj.dao"
- targetProject=".\src">
- <!-- enableSubPackages: 是否让 schema 作为包的后缀 -->
- <property name="enableSubPackages" value="false" />
- </javaClientGenerator>
- <!-- 指定数据库表 -->
- <table tableName="items"></table>
- <table tableName="user"></table>
- <!-- <table schema=""tableName="sys_user"></table>
- <table schema=""tableName="sys_role"></table>
- <table schema=""tableName="sys_permission"></table>
- <table schema=""tableName="sys_user_role"></table>
- <table schema=""tableName="sys_role_permission"></table> -->
- <!-- 有些表的字段需要指定 java 类型
- <table schema=""tableName="">
- <columnOverride column=""javaType="" />
- </table> -->
- </context>
- </generatorConfiguration>
1.3: 创建启动类
这里需要配置 generatorConfig.xml 文件所在路径, 并运行此类
- package cn.clj.start;
- import java.io.File;
- import java.util.ArrayList;
- import java.util.List;
- import org.mybatis.generator.api.MyBatisGenerator;
- import org.mybatis.generator.config.Configuration;
- import org.mybatis.generator.config.xml.ConfigurationParser;
- import org.mybatis.generator.internal.DefaultShellCallback;
- public class StartGenerator {
- public void generator() throws Exception{
- List<String> warnings = new ArrayList<String>();
- boolean overwrite = true;
- File configFile = new File("config/generatorConfig.xml");
- ConfigurationParser cp = new ConfigurationParser(warnings);
- Configuration config = cp.parseConfiguration(configFile);
- DefaultShellCallback callback = new DefaultShellCallback(overwrite);
- MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
- callback, warnings);
- myBatisGenerator.generate(null);
- }
- public static void main(String[] args) throws Exception {
- try {
- StartGenerator startService = new StartGenerator();
- startService.generator();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
自动生成的文件
2, 定义接口和实现类
- package cn.clj.service;
- import java.util.List;
- import cn.clj.pojo.Items;
- public interface ItemsService {
- public List<Items> list() throws Exception;
- }
注意: 这里注入了 Mapper 接口, 并开启了自动扫描注解
- package cn.clj.service;
- import java.util.List;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import cn.clj.dao.ItemsMapper;
- import cn.clj.pojo.Items;
- import cn.clj.pojo.ItemsExample;
- @Service
- public class ItemsServiceImpl implements ItemsService{
- @Autowired
- private ItemsMapper itemsMapper;
- @Override
- public List<Items> list() throws Exception {
- //selectByExampleWithBLOBs(example)包含文本类型
- ItemsExample example=new ItemsExample();
- //example.createCriteria()可以创建查询条件; 如果无需任何查询条件, 直接将 example 实例化即可
- List<Items> list=itemsMapper.selectByExampleWithBLOBs(example);
- return list;
- }
- }
3, 创建 conroller 类
- @Controller
- public class ItemController {
- // 注意: 这里可以使用 Autowired: 自动装配(缺点: 当一个接口有两个实现类时就无法世识别)
- //Resource: 值是取实现类中定义的注解值
- @Autowired
- private ItemsService itemsService;
- // 查询所有
- @RequestMapping("/list")
- public ModelAndView itemsList() throws Exception{
- List<Items> list=itemsService.list();
- ModelAndView modelAndView=new ModelAndView();
- modelAndView.addObject("itemList",list);
- modelAndView.setViewName("itemList");
- return modelAndView;
- }
- }
4, 创建 itemList.jsp 接受参数
- <%@taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
- <body>
- <form action="${pageContext.request.contextPath }/search.action" method="post">
查询条件:
- <table width="100%" border=1>
- <tr>
- <!-- 如果 controller 接受的是 vo, 那么页面上 input 框中 name 属性值要等于 vo 属性. 属性 (..)进行引用 -->
- <td > 商品名称:<input type="text" name="items.name"/></td>
- <td > 商品价格:<input type="text" name="items.price"/></td>
- <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="${itemList}" 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 }/itemEdit.action?id=${item.id}">修改</a></td>
- </tr>
- </c:forEach>
- </table>
- </form>
- </body>
5, 测试: http://localhost:8080 / 项目名 / list.action
五, SpringMvc 值参数绑定
1, 关于 @RequestParam 标签
1) 使用 @RequestParam 常用于处理简单类型的绑定
如: jsp 传入一个值
<input type="text" name="item_id"/>
controller 接收
- public String editItem(@RequestParam(value="item_id",required=true) String id) {
- }
注意:
1.1 ) value: 参数名字, 即入参的请求参数名字, 形参名称为 id, 但是这里使用 value="item_id" 限定请求的参数名为 item_id, 所以页面传递参数的名必须为 item_id. 如果请求参数中没有 item_id 将跑出异常:
HTTP Status 500 - Required Integer parameter 'item_id' is not present
1.2)这里通过 required=true 限定 item_id 参数为必需传递, 如果不传递则报 400 错误, 可以使用 defaultvalue 设置默认值, 即使 required=true 也可以不传 item_id 参数值
2, 绑定普通类型
需求 1: 打开编辑界面, 查看商品详情
环境: 引用以上环境, 当触发 itemList.jsp 中的修改按钮, 根据超链接跳转, 传入参数为商品 id
1), 编写接口和实现类
- public Items findItemsById(Integer id) throws Exception
- package cn.clj.service;
- import java.util.List;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import cn.clj.dao.ItemsMapper;
- import cn.clj.pojo.Items;
- import cn.clj.pojo.ItemsExample;
- @Service
- public class ItemsServiceImpl implements ItemsService{
- @Autowired
- private ItemsMapper itemsMapper;
- @Override
- public Items findItemsById(Integer id) throws Exception {
- Items items=itemsMapper.selectByPrimaryKey(id);
- return items;
- }
- }
2), 编写 controller
参数通过域名封装到请求中, 此时可以在方法中定义 HttpServletRequest,HttpSession,Model 将参数获得
注意: 这里设置返回页面是个字符串
- package cn.clj.controller;
- import java.util.Date;
- import java.util.List;
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- 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.servlet.ModelAndView;
- import cn.clj.pojo.Items;
- import cn.clj.service.ItemsService;
- import cn.clj.vo.QueryVo;
- @Controller
- public class ItemController {
- // 注意: 这里可以使用 Autowired: 自动装配(缺点: 当一个接口有两个实现类时就无法世识别)
- //Resource: 值是取实现类中定义的注解值
- @Autowired
- private ItemsService itemsService;/**
- * springMvc 默认支持的参数类型, 也就是说在 controller 方法中可以加入这些, 也可以不加
- * HttpServletRequest
- * HttpServletResponse
- * HttpSession
- * Model
- */
- @RequestMapping("/itemEdit")
- public String itemEdit(HttpServletRequest request,Model model) throws Exception{
- String idStr=request.getParameter("id");
- Items items=itemsService.findItemsById(Integer.parseInt(idStr));
- //Model 模型: 模型中放入了返回给页面的数据
- //Model 底层就是用的 request 域传递数据, 但是对 request 进行了扩展
- model.addAttribute("item",items);
- // 如果 springMvc 方法返回一个简单的 string 字符串, 那么 springMvc 就会认为这个字符串就是页面的名称
- return "editItem";
- }
- }
3), 创建 editItem.jsp 接受参数
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
- <body>
- <!-- 上传图片是需要指定属性 enctype="multipart/form-data" -->
- <!-- <form id="itemForm" action=""method="post"enctype="multipart/form-data"> -->
- <form id="itemForm" action="${pageContext.request.contextPath }/updateitem.action" method="post">
<input type="hidden" name="id" value="${item.id }" /> 修改商品信息:
- <table width="100%" border=1>
- <tr>
- <td > 商品名称</td>
- <td><input type="text" name="name" value="${item.name }" /></td>
- </tr>
- <tr>
- <td > 商品价格</td>
- <td><input type="text" name="price" value="${item.price }" /></td>
- </tr>
- <tr>
- <td > 商品简介</td>
- <td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea>
- </td>
- </tr>
- <tr>
- <td colspan="2" align="center"><input type="submit" value="提交" />
- </td>
- </tr>
- </table>
- </form>
- </body>
绑定 pojo 类型
需求 2, 更新数据
1), 前提有 pojo 类(其中在修改界面中的接受的 Items 的属性必须与 pojo 类中的属性保持一致)
- package cn.clj.pojo;
- 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;
- // 省略 set/get 方法
- }
1), 创建接口和实现类
- public void updateItems(Items items) throws Exception;
- @Service
- public class ItemsServiceImpl implements ItemsService{
- @Autowired
- private ItemsMapper itemsMapper;
- @Override
- public void updateItems(Items items) throws Exception {
- // TODO Auto-generated method stub
- // 此方法包含大对象文本
- itemsMapper.updateByPrimaryKeyWithBLOBs(items);
- }
- }
2), 创建 conroller 类定义方法
- @Controller
- public class ItemController {
- // 注意: 这里可以使用 Autowired: 自动装配(缺点: 当一个接口有两个实现类时就无法世识别)
- //Resource: 值是取实现类中定义的注解值
- @Autowired
- private ItemsService itemsService;/**
- * 更新数据
- * @return
- *$/1.springMvc 可以直接接受基本数据类型, 包括 string,spring Mvc 可以帮你自动进行类型转换
- //controller 方法接受的参数的变量名称必须要等于页面上 input 框的 name 属性值
- //2.springMvc 可以直接接受 pojo 类型, 要求页面上 input 框的 name 属性名称必须等于 pojo 的属性名称
- @RequestMapping("/updateitem")
- public String updateitem(Items items) throws Exception{ // 方式二
- //public String updateitem(Integer id,String name,Float price,String detail) throws Exception{ // 方式一
- // Items items=new Items();
- // items.setId(id);
- // items.setName(name);
- // items.setPrice(price);
- // items.setDetail(detail);
- // 注意: 这里 jsp 源代码中屏蔽了接受时间的框, 是因为 String 类型可以转换为基本类型, 但是 string 类型不能转换为 Date 类型
- items.setCreatetime(new Date());// 数据库字段定义为非空
- itemsService.updateItems(items);
- return "success";
- }
- }
- 3), 创建 success.jsp 页面
- <body>
- <h3 > 更新成功</h3>
- </body>
- 解决中文乱码问题
- 1)针对 post 请求
- post 请求是封装于服务器端, 请求参数不会在域名中出现
- 在 web.xml 中配置过滤器, 当服务器启动时就对请求中的参数进行字符编码转换
- <!-- 解决 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>
- 2)针对 get 请求
- get 请求是响应在地址栏中, 通过地址栏可以看到请求参数
- 将 controller 类中接受到的包含中文参数进行字符编码转换
- String name=new String(request.getAttribute("参数名").getBytes("iso-8859-1"),"utf-8"));
- 绑定包装类
- 需求 3: 使用包装类接受高级查询条件中所传过来的值
- 1) 定义 VO
- package cn.clj.vo;
- import java.util.Arrays;
- import java.util.List;
- import cn.clj.pojo.Items;
- /**
- * 演示高级查询, 封装指定 pojo 类中的指定属性
- * @author 佳先森
- *
- */
- public class QueryVo {
- // 商品对象
- private Items items;
- // 省略 set/get,toString 方法
- }
2) 定义 jsp
<form action="${pageContext.request.contextPath }/search.action" method="post">
查询条件:
- <table width="100%" border=1>
- <tr>
- <!-- 如果 controller 接受的是 vo, 那么页面上 input 框中 name 属性值要等于 vo 属性. 属性 (..)进行引用 -->
- <td > 商品名称:<input type="text" name="items.name"/></td>
- <td > 商品价格:<input type="text" name="items.price"/></td>
- <td><input type="submit" value="查询"/></td>
- </tr>
- </table>
3) controller 类中定义方法
- @Controller
- public class ItemController {
- // 如果 controller 接受的是 vo, 那么页面上 input 框中 name 属性值要等于 vo 属性. 属性 (..)进行引用
- @RequestMapping("/search")
- public String search(QueryVo vo) throws Exception{
- System.out.println(vo);
- return "";
- }
自定义参数绑定
需求: 接受参数为时间格式
分析: 为什么输入框为时间格式的 conroller 接收时会报错呢, 是因为 spring MVC 能够将自动将字符串转换为原始型和包装类型, 但是它不能讲时间格式的转换为字符串(时间格式有多种), 不然会报错, 这里只能为时间格式自定义参数绑定
1) 创建工具类
- package cn.controller.converter;
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import org.springframework.core.convert.converter.Converter;
- /**
- * 自定义全局字符串转日期转换器
- * param:s -source: 源
- * param:T -target: 目标
- * 还需在 springMv 中配置此工具类
- * @author 佳先森
- *
- */
- public class CustomGlobalStrToDateConverter implements Converter<String,Date>{
- @Override
- public Date convert(String source) {
- try {
- Date date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(source);
- return date;
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
- }
2) 在 SpringMVc 上创建自定义转换器, 并将它配置到注解驱动上
- <!-- 注解驱动: 能够自动配置最新版的处理器映射器和处理器适配器 -->
- <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
- <!-- 配置自定义转换器: 用于将字符串转换为日期格式
- 步骤: 1. 编写工具类 2. 将自定义的转换器配置到注解驱动上
- -->
- <bean id="conversionService"
- class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
- <property name="converters">
- <set>
- <!-- 指定自定义转换器的全路径名名称 -->
- <bean class="cn.controller.converter.CustomGlobalStrToDateConverter"/>
- </set>
- </property>
- </bean>
3) jsp 界面
注意引入 jstl/fmt 标签, 这是能够在界面中对时间内容进行格式整理
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
- <form id="itemForm" action="${pageContext.request.contextPath }/updateitem.action" method="post">
- <table width="100%" border=1>
- <tr>
- <td > 商品生产日期</td>
- <td><input type="text" name="createtime"
- value="<fmt:formatDate value="${item.createtime}"pattern="yyyy-MM-dd HH:mm:ss"/>" /></td>
- </tr>
- </table>
- </form>
4) controller 接收方法
- @RequestMapping("/updateitem")
- public String updateitem(Items items,Model model) throws Exception{
- itemsService.updateItems(items);
- return "success";
- }
六, spring MVC 与 struts 2 区别
1, springmvc 的入口是一个 servlet 即前端控制器, 而 struts2 入口是一个 filter 过虑器.
2, springmvc 是基于方法开发(一个 url 对应一个方法), 请求参数传递到方法的形参, 可以设计为单例或多例(建议单例),struts2 是基于类开发, 传递参数是通过类的属性, 只能设计为多例.
3, Struts 采用值栈存储请求和响应的数据, 通过 OGNL 存取数据, springmvc 通过参数解析器是将 request 请求内容解析, 并给方法形参赋值, 将数据和视图封装成 ModelAndView 对象, 最后又将 ModelAndView 中的模型数据通过 reques 域传输到页面. Jsp 视图解析器默认使用 jstl.
七, spring MVC 高级参数绑定
1, 绑定数组
需求: 演示批量删除
1) 定义 jsp
jsp 中包含一个 form 表单, 多个 input 框前有个 checkbox 复选框
<form action="${pageContext.request.contextPath }/delAll.action" method="post">
查询条件:
- <table width="100%" border=1>
- <tr>
- <!-- 如果 controller 接受的是 vo, 那么页面上 input 框中 name 属性值要等于 vo 属性. 属性 (..)进行引用 -->
- <td > 商品名称:<input type="text" name="items.name"/></td>
- <td > 商品价格:<input type="text" name="items.price"/></td>
- <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="${itemList}" var="item">
- <tr>
- <!-- 批量删除: name 属性名称等于 vo 中的接受的属性名称 -->
- <td>
- <input type="checkbox" name="ids" value="${item.id}"/>
- </td>
- <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 }/itemEdit.action?id=${item.id}">修改</a></td>
- </tr>
- </c:forEach>
- </table>
- </form>
2)定义 controller 中的方法
这里是通过复选框将选中的数据进行传送, controller 方法中得用数组来接收
方式一: 数组作为参数进行接收: 注意这里属性名 (ids) 要与复选框保持一致
- // 如果批量删除, 一堆 input 复选框, 那么可以提交数据(只有被选中的时候才可以提交)
- @RequestMapping("/delAll")
- public String delAll(String[] ids) throws Exception{
- System.out.println(ids.toString());
- return "";
- }
方式二: 将数组作为属性封装到 VO 对象中, 将 VO 对象作为参数进行接收
- public class QueryVo {
- // 商品对象
- private Items items;
- // 批量删除
- private Integer[] ids;
- // 省略 set/get 方法
- }
- // 如果批量删除, 一堆 input 复选框, 那么可以提交数据(只有被选中的时候才可以提交)
- @RequestMapping("/delAll")
- public String delAll(QueryVo vo) throws Exception{
- System.out.println(vo.getItems().getName());
- System.out.println(queryVo.getItems().getPrice());
- return "";
- }
2, 绑定集合(将表单的数据绑定到 List 中)
需求: 对数据进行批量修改
1) 在 pojo 类中定义一个集合的属性
- package cn.clj.vo;
- import java.util.Arrays;
- import java.util.List;
- import cn.clj.pojo.Items;
- /**
- * 演示高级查询, 封装指定 pojo 类中的指定属性
- * @author 佳先森
- *
- */
- public class QueryVo {
- // 商品对象
- private Items items;
- // 用户对象
- //....
- // 批量删除
- private Integer[] ids;
- // 批量修改
- private List<Items> itemsList;
- // 省略 set/get,toString()方法
- }
2)更改 jsp
<form action="${pageContext.request.contextPath }/updateAll.action" method="post">
查询条件:
- <table width="100%" border=1>
- <tr>
- <!-- 如果 controller 接受的是 vo, 那么页面上 input 框中 name 属性值要等于 vo 属性. 属性 (..)进行引用 -->
- <td > 商品名称:<input type="text" name="items.name"/></td>
- <td > 商品价格:<input type="text" name="items.price"/></td>
- <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="${itemList}" var="item" varStatus="status">
- <tr>
- <!-- 如果批量修改, 可以用 List<pojo > 来接受, 页面上 input 框的 name 属性值 = vo 中的接受的属性名称 +[list 的下标]+.+list 泛型属性的名称 -->
- <td>
- <input type="checkbox" name="ids" value="${item.id}"/>
- <input type="hidden" name="itemsList[${status.index}].id" value="${item.id}"/>
- </td>
- <td><input type="text" name="itemsList[${status.index}].name" value="${item.name}"/></td>
- <td><input type="text" name="itemsList[${status.index}].price" value="${item.price}"/></td>
- <td><input type="text" name="itemsList[${status.index}].createtime" value="<fmt:formatDate value="${item.createtime}"pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
- <td><input type="text" name="itemsList[${status.index}].detail" value="${item.detail}"/></td>
- <td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
- </tr>
- </c:forEach>
- </table>
- </form>
3)在 controller 类中创建接受方法
- // 批量修改
- @RequestMapping("/updateAll")
- public String updateAll(QueryVo vo) throws Exception{
- System.out.println(vo.getItems().getName());
- System.out.println(vo.getItems().getPrice());
- return "";
- }
八, 关于 spring MVC 窄化请求映射
分析: 在团队开发情况下, 不同 controller 中可能出现一个或多个方法 RequestMapping 值相同, 因为配置文件中采用的是包扫描的方法进行映射, 就有可能在输入域名的时候跳错 controller 中的方法. 此时, 如果为了区分每个 conroller 中的每个方法, 必须配置窄化请求映射, 相当于给类起个名字, 每当反问域名时, 指定跳转方法 uri 前必须加上这个 "类名", 通过此方法对类行进分类管理
如:
- @Controller
- // 窄化请求映射: 为防止方法名重名, 相当于在 url 中多加了一层目录, 房子重名
- @RequestMapping("/items")
- public class ItemController {
- // 批量修改
- @RequestMapping("/updateAll")
- public String updateAll(QueryVo vo) throws Exception{
- System.out.println(vo);
- return "";
- }
如果以后要跳转到该方法, 域名得写成 http://localhost:8080 / 项目名 / items/updateAll.action
九, spring MVC 之请求方法限定
语法为 @RequestMapping(value="/XXX",method=RequestMethod.XX), 其中 XX 可以写 GET 或者 POST, 如果在方法中限定了请求方法而 jsp 中表单提交方式不是指定的, 会报 405 错误
- @RequestMapping(value="/list",method=RequestMethod.GET)
- public ModelAndView itemsList() throws Exception{
- List<Items> list=itemsService.list();
- System.out.println("进入了");
- ModelAndView modelAndView=new ModelAndView();
- modelAndView.addObject("itemList",list);
- modelAndView.setViewName("itemList");
- return modelAndView;
- }
十, controller 类方法返回值
controller 方法返回值包含多种, 一下介绍几种常用的:
1,ModelAndView 方式
- @RequestMapping(value="/list",method=RequestMethod.GET)
- public ModelAndView itemsList() throws Exception{
- List<Items> list=itemsService.list();
- ModelAndView modelAndView=new ModelAndView();
- modelAndView.addObject("itemList",list);
- modelAndView.setViewName("itemList");
- return modelAndView;
- }
2,String 方式(直接 return 一个字符串), 返回的数据由 model 完成
种类一: 放回普通字符串(去掉页面扩展名)
- @RequestMapping("/search")
- public String search(QueryVo vo) throws Exception{
- System.out.println(vo);
- return "success";
- }
种类二: 请求转发方式
注意: 这里是请求转发跳转到同一个 Controller 中的注解值为 itemEdit 的方法, 请求转发能够携带值
- @RequestMapping("/updateitem")
- public String updateitem(Items items,Model model) throws Exception{
- itemsService.updateItems(items);// 请求转发: 浏览器中的 url 不发生改变, request 域中的数据可以带到转发后的方法中
- model.addAttribute("id",items.getId());// 或者: request.setAttribute("id",items.getId())
- //springMvc 中请求转发: 返回的字符串以 forward: 开头的都是请求转发
- return "forward:itemEdit.action";
- }
种类三: 重定向方式
注意: 重定向的方式是不能携带值的, 如果要传参数, 得封装到域名中(如: return "redirect:itemsEdit.action?id="+items.getId())
- @RequestMapping("/updateitem")
- public String updateitem(Items items,Model model) throws Exception{
- itemsService.updateItems(items);
- model.addAttribute("id",items.getId());// 在 springMvc 中凡是以 redirect: 字符串开头的的都是重定向
- return "redirect:itemsEdit.action";
- }
种类三: 返回值为 void
这里演示的请求请求转发的方式(如果 controller 方法返回值为 void, 则不走 SpringMvc 组件, 需要些完整的路径名称))
- @RequestMapping("/updateitem")
- public void updateitem(Items items,HttpServletRequest request,HttpServletResponse response) throws Exception{
- itemsService.updateItems(items);
- request.setAttribute("id",items.getId())
- request.getRequestDispatcher("/jsp/success.jsp").forward(request, response);
- }
十一, spring MVC 之全局异常处理
需求: 当条件查询询信息时出现错误(没有该商品), 都会跳转到指定的错误页面
1, 定义异常类
- package cn.clj.vo;
- public class CustomerException extends Exception{
- // 异常信息
- private String message;
- public CustomerException(String message) {
- super();
- this.message = message;
- }
- // 省略 set/get 方法
- }
2, 定义异常处理工具类
public class GlobalExceptionResolver implements HandlerExceptionResolver{
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- ex.printStackTrace();
- CustomerException customerException=null;
- if(ex instanceof CustomerException){
- customerException=(CustomerException) ex;
- }else{
- customerException=new CustomerException("系统错误, 请联系管理员");
- }
- ModelAndView model=new ModelAndView();
- model.addObject("message",customerException);
- model.setViewName("error");
- return model;
- }
- }
3, 创建异常页面 error.jsp
<body>
您的操作出现错误如下:<br/>
- <h3><font color="red">${message}</font></h3>
- </body>
4, 配置异常处理(在 SpingMvc.xml 文件中配置处理器)
- <!-- 异常处理器 -->
- <bean id="handlerExceptionResolver" class="cn.clj.vo.CustomerException"/>
- </beans>
5, 利用异常类
在调用查询方法时, 如果查询到的商品不存在, 抛出自定义异常类
- @RequestMapping("/itemEdit")
- public String itemEdit(HttpServletRequest request,Model model) throws Exception{
- String idStr=request.getParameter("id");
- Items items=itemsService.findItemsById(Integer.parseInt(idStr));
- if(items==null){
- throw new CustomerException("您查询的信息不存在");
- }
- model.addAttribute("item",items);
- return "editItem";
- }
6, 测试
当查询一个不存在的商品, 如果成功跳转到自定义异常界面, 表示配置成功
十二, spring MVC 之上传图片
分析: 企业中像那种高并发项目, 都会有不同的服务器接受不同资源, 利用 nginx 实现负载均衡. 这里因为只上传图片, 服务器只有 tomcat, 所以只能在 tomcat 中配置.
1, 配置虚拟存储路径
此配置就是将上传的图片放置到指定的文件夹下
做法: 进入 tomcat/conf/server.xml 文件中, 加入下面一条命令, 表示到域名以 pic 结尾时, 访问的目录为 E:\ 壁纸文件夹下
<Context docBase="E:\ 壁纸" path="/pic" reloadable="false"/>
2, 加入文件上传依赖 jar 包
3, 在 SqlMapConfig.xml 中配置文件上传解析器
- <!-- 文件上传 -->
- <bean id="multipartResolver"
- class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
- <!-- 设置上传文件的最大尺寸为 5MB -->
- <property name="maxUploadSize">
- <value>5242880</value>
- </property>
- </bean>
4, 在 Controller 中创建文件上传处理方法
文件上传是通过表单提交的, 所提交的是一连串字符串, 需对字符串进行处理, 这里为了防止所存的图片文件重名, 采用了随机字符串进行拼接
- // 演示上传图片: 注意 "pictureFile" 是与 jsp 中文件上传属性保持一致
- @RequestMapping("/upload")
- public String upload(MultipartFile pictureFile,Items items,Model model) throws Exception{
- //1. 获取图片完整名称
- String fileStr=pictureFile.getOriginalFilename();
- //2. 使用随机生成的字符串 + 源图片扩张名组成新的图片名称, 防止图片重名
- String newFileName=UUID.randomUUID().toString()+fileStr.substring(fileStr.lastIndexOf("."));
- //3. 将图片保存到硬盘
- pictureFile.transferTo(new File("E:\\ 壁纸 \\"+newFileName));
- //4. 将图片名称保存到数据库
- items.setPic(newFileName);
- itemsService.updateItems(items);
- return "success";
- }
5, 创建具有图片上传的 form 表单的 jsp 页面
- <form id="itemForm" action="${pageContext.request.contextPath }/upload.action" method="post" enctype="multipart/form-data">
- <table width="100%" border=1>
- <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 colspan="2" align="center"><input type="submit" value="提交" />
- </td>
- </tr>
- </table>
- </form>
十三, spring MVC 之 Json
spring MVC 是支持 Json 格式的, 需要配置 @RequestBody
@RequestBody 注解用于读取 http 请求的内容(字符串), 通过 springmvc 提供的 HttpMessageConverter 接口将读到的内容转换为 json,xml 等格式的数据并绑定到 controller 方法的参数上.
需求: 利用 ajax 传送 json 数据, contoller 类定义方法进行接受, 并进行相应
1, 导入 json 依赖 jar 包
2, 必须有注解驱动, 基于上面环境已经配置, 这里无须再配置
- <!-- 注解驱动: 能够自动配置最新版的处理器映射器和处理器适配器 -->
- <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
3, 导入 jquery 依赖 jar 包
4,jsp 中调用 ajax 请求
这里当触发 input 按钮, 就会调用 ajax 请求
- <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js">
- </script>
- <script type="text/javascript">
- function sendJson() {
- $.ajax({
- type: "post",
- url: "${pageContext.request.contextPath }/sendJson.action",
- <!--ajax默认以text文本形式传递,
- 如果要传递json的指定为json-->contentType: "application/json;charset=utf-8",
- data: '{"name":" 测试商品 ","price":99.9}',
- success: function(data) {
- alert(data);
- }
- });
- }
- </script>
- <input type="button" value="sendJson" onClick="sendJson()" />
5, 参数接受
- // 导入 jackson 的 jar 包在 controller 的方法中可以使用 @RequestBody,
- // 让 springMvc 将 json 格式字符串自动转换我 java 中 pojo
- // 注意: 页面 json 中 key 要等于 java 中 pojo 的属性名称
- //controller 方法返回 pojo 类型的对象并且用 @ResponseBody 注解, springMvc 会自动将 pojo 对象转换为 json 格式字符串
- @RequestMapping("/sendJson")
- @ResponseBody
- public Items sendJson(@RequestBody Items items) throws Exception{
- //public void sendJson(@RequestBody Items items) throws Exception{
- System.out.println(items.getName()+"\t"+items.getPrice());
- // 方式一, 返回值为 void 这里无须设置跳转页面, ajax 会自动跳转
- // 方式二: 返回值为 Items pojo 类, 方法中参数必须配置 @ResponseBody 注解, 会给界面返回 Item 对象
- return items;
- }
十四, spring MVC 之 Restful 风格
1, 什么是 Restfull 风格
一种软件架构风格, 设计风格而不是标准, 只是提供了一组设计原则和约束条件. 它主要用于客户端和服务器交互类的软件. 基于这个风格设计的软件可以更简洁, 更有层次, 更易于实现缓存等机制.
------ 360 百科
简而言之: Restful 就是一个资源定位及资源操作的风格. 不是标准也不是协议, 只是一种风格, 是对 http 协议的诠释.
资源定位: 互联网所有的事物都是资源, 要求 url 中没有动词, 只有名词. 没有参数
Url 格式: http://blog.csdn.net/beat_the_world/article/details/45621673
资源操作: 使用 put,delete,post,get, 使用不同方法对资源进行操作. 分别对应添加, 删除, 修改, 查询. 一般使用时还是 post 和 get.Put 和 Delete 几乎不用.
2, 怎么使用 Restful
需求: 更改访问路径格式, 采用 Restful 风格
1) 配置 restful 配置
此时需要更改 web.xml 文件中的拦截对象, 以前是针对所有的 action("*.action"), 现在是针对所有对象("/")
- <!-- 开启 SpringMVc 拦截器 -->
- <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>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>SpringMvc</servlet-name>
- <!--
- *.action: 代表拦截后缀名为. action 结尾的
- / : 拦截所有但是不包括. jsp
- /* : 拦截所有包括. jsp
- -->
- <url-pattern>/</url-pattern>
- </servlet-mapping>
2) jsp 请求书写规范
这里是传递了一个 id 参数, 请求域名中去掉了 aciton 或者特殊符号
<a href="${pageContext.request.contextPath }/restful/${item.id}">修改</a>
3) 接受参数
通过 @RequestMapping("/restful/{id}")接收具有 restful 风格的域名;@PathVariable 接受参数值
- // 通过 @PathVariable 可以接收 url 中所传过来的参数
- //@RequestMapping("/restful/{id}/{张三}")传多参
- //@RequestMapping("/restful/{id}")中接受参数使用大括号中加上变量名称,@PathVariable 中变量名称要和 @RequestMapping 中变量名称保持一致
- @RequestMapping("/restful/{id}")
- public String restful(@PathVariable("id") Integer id,HttpServletRequest request,Model model) throws Exception{
- // public String restful(@PathVariable("id") Integer id,@PathVariable("张三") String name,HttpServletRequest request,Model model) throws Exception{
- Items items=itemsService.findItemsById(id);
- model.addAttribute("item",items);
- return "editItem";
- }
十五, spring MVC 之拦截器
1, 怎么定义一个拦截器
1) 创建一个自定义拦截器类, 继承 HandlerInterceptor 接口
- package cn.clj.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 Interceptor1 implements HandlerInterceptor{
- // 执行实际: Controller 以及执行, ModelAndView 已经返回
- // 使用场景: 记录操作日志(如记录用户登录的 ip, 时间等)
- @Override
- public void afterCompletion(HttpServletRequest arg0,
- HttpServletResponse arg1, Object arg2, Exception arg3)
- throws Exception {
- System.out.println("afterCompletion");
- }
- // 执行实际: Controller 方法已经执行, ModelAndView 还没返回
- // 使用场景: 可以再次方法中设置全局的数据处理业务, 这里有个 ModelAndView, 可以添加全局参数
- @Override
- public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
- Object arg2, ModelAndView arg3) throws Exception {
- // TODO Auto-generated method stub
- System.out.println("postHandle");
- }
- // 返回 boolean 值: 如果返回 true: 放行; false: 拦截
- // 执行时机: controller 方法没有被执行, ModelAndView 没有被返回
- // 使用场景: 权限验证
- @Override
- public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
- Object arg2) throws Exception {
- // TODO Auto-generated method stub
- System.out.println("preHandle");
- return true;
- }
- }
2) 在 springMvc.xml 配置拦截器(这里是配置全局拦截器)
- <!-- 配置拦截器 -->
- <mvc:interceptors>
- <mvc:interceptor>
- <!-- 拦截请求的路径要拦截所有必须配置成 /**(不能是 /*, 它只拦截一层目录) -->
- <mvc:mapping path="/**"/>
指定拦截器的位置
- <bean class="cn.clj.interceptor.Interceptor1"/>
- </mvc:interceptor>
- </mvc:interceptors>
3)启动 tomcat, 就会自动调用拦截器
2, 拦截器应用之登录(身份认证)
分析: 在登录界面中, 当用户输入自己信息时, 会调用后端方法, 拦截器检查 session 中否存在这个用户, 核对数据库是否有这个用户, 然后进行处理放心还是拦截
1) 定义一个登录的拦截器
- package cn.clj.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{
- @Override
- public void afterCompletion(HttpServletRequest arg0,
- HttpServletResponse arg1, Object arg2, Exception arg3)
- throws Exception {
- // TODO Auto-generated method stub
- }
- @Override
- public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
- Object arg2, ModelAndView arg3) throws Exception {
- // TODO Auto-generated method stub
- }
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
- Object arg2) throws Exception {
- // 判断当前访问路径是否为登录的路径, 如果是则放行
- if(request.getRequestURI().indexOf("/login")>0){
- return true;
- }
- // 判断 session 中是否有登录信息, 如果没有则跳转到登录界面, 如果有则放行
- HttpSession session=request.getSession();
- if(session.getAttribute("username")!=null){
- return true;
- }
- request.getRequestDispatcher("/jsp/login.jsp").forward(request, response);
- // 其他则拦截
- return false;
- }
- }
2) 定义一个 jsp 登录界面
- <form action="${pageContext.request.contextPath}/login/submit" method="post">
- <table>
- <tr>
- <td > 用户名:<input type="text" name="username"/></td></br>
- <td > 密 码:<input type="text" name="password"/></td></br>
- <td><input type="submit" value="登录"/></td>
- </tr>
- </table>
- </form>
3) 定义处理登录的 controller 类
- package cn.clj.controller;
- import java.io.File;
- import java.util.Date;
- import java.util.List;
- import java.util.UUID;
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.ResponseBody;
- import org.springframework.web.multipart.MultipartFile;
- import org.springframework.web.servlet.ModelAndView;
- import cn.clj.pojo.Items;
- import cn.clj.service.ItemsService;
- import cn.clj.vo.QueryVo;
- @Controller
- @RequestMapping("/login")
- public class LoginController {
- // 跳转到登录页面
- @RequestMapping("/login")
- public String login() throws Exception{
- return "login";
- }
- @RequestMapping("/submit")
- public String submit(String username,String password,HttpServletRequest request) throws Exception{
- HttpSession session=request.getSession();
- // 判断用户名密码正确性, 如果正确则将登录信息放入 session 中
- // 这里简写, 真正项目中要去数据库中校验用户名和密码
- if(username!=null){
- session.setAttribute("username", username);
- }
- // 跳转到列表页(注意: 这里加了斜杠是用了绝对路径, 因为
- // 两者不属于同一个 controller, 如果跳转的 conrtoller
- // 类前加了窄化请求映射, 路径名得为 redirect:/items/list)
- return "redirect:/list";
- }
- }
通过此方法对 url 进行分类管理.
来源: https://www.cnblogs.com/cailijia52o/p/8732906.html