SpringMVC学习笔记_02
1、springmvc对多视图的支持
(1)导入xml格式视图支持的jar包
注意:springmvc本身就支持xml格式,所以不用导入其他支持的jar包了。
(2)在springmvc.xml中配置支持多视图
<!-- 配置支持多视图 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<!-- 配置支持的媒体类型 -->
<!-- spring3.2后改成如下配置 -->
<property name="contentNegotiationManager">
<bean class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<!-- 指定多个媒体类型 -->
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"></entry>
<entry key="xml" value="application/xml"></entry>
<!-- <entry key="pdf" value="application/pdf"></entry> 需要额外的jar包 -->
</map>
</property>
</bean>
</property>
<!-- 指定默认的视图 -->
<property name="defaultViews">
<!-- 支持多个视图 -->
<list>
<!-- 对json格式视图的支持 -->
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"></bean>
<!-- 对xml格式视图的支持,需要注入构造函数,需要一个jar包:spring-oxm-3.2.0.RELEASE.jar -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<!-- 配置对哪些类进行xml转换的支持,即绑定多个类,演示代码中我们只绑定了一个类 -->
<property name="classesToBeBound">
<list>
<!-- 注意:需要在绑定的类中加入对xml格式视图转换的注解:@XmlRootElement -->
<value>com.itheima.domain.User</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
</bean>
小结:通过以上配置,模拟了WebService对多视图的支持的功能。
(3)配置javabean,即在绑定的类User中加入对xml格式视图转换的注解:@XmlRootElement
(4)在web.xml中配置约定访问的url
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
(5)定义Controller
// 多视图支持
// 返回的是对象,把返回的对象转换成json格式视图和xml格式的视图
@RequestMapping("multiView")
public User multiView() {
User user1 = new User();
user1.setId(1);
user1.setUsername("晓艺");
user1.setAge("26");
user1.setAddress("物资学院");
user1.setBirthday(new Date());
return user1;
}
(6)访问
根据官方文档约定:访问的时候需要加上响应的扩展名。
即:访问json格式的数据,需要加上json扩展名;访问html格式的数据,需要加上html的扩展名;访问xml格式的数据,需要加上xml的扩展名。
根据我们web.xml文件的访问约定:扩展名.do是访问jsp页面的。
我们约定rest目录下所有以json和xml扩展名都支持相应的视图。
我们访问json格式数据的访问形式如下:
我们访问xml格式数据的访问形式如下:
(7)<mvc:annotation-driven/>
<mvc:annotation-driven/> 默认创建:注解处理器映射器、注解处理器适配器、并提供对json格式数据的支持。
在springmvc.xml中进行配置:
<!-- 表示默认创建:处理器映射器对象、处理器映射器对象,还表示默认启动json格式数据的支持 -->
<mvc:annotation-driven />
但是注意:此时javaBean不能添加注解@XmlRootElement了。@XmlRootElement表示提供对xml视图支持。
2、SSM整合小案例
2.0、需求
- 实现商品查询列表,从mysql数据库中查询商品信息。
2.1、使用eclipse,创建一个动态web工程并导入jar包
- 其中Dynamic web module version版本选择 2.5,这样兼容性好一些;
- Default output folder设置为 WebRoot\WEB-INF\classes
- Content directory设置为 WebRoot
- 更改JRE System Library[J2SE-1.5]为 JRE System Library[jre1.7.0_80]
- 删掉没用的库:EAR Libraries
- 增加服务器运行环境库 Server Runtime,不然jsp文件会报错。
- 创建完项目后,将整个项目的编码改为UTF-8。
- 操作步骤:选中项目右键 --> Properties --> Resource --> Text file encoding --> Other中选择UTF-8。
- 对于动态的java web项目,为了工程目录结构的清爽,我们将引入的jar包放到“Web App Libraries”中,可以通过“小三角”选择是否“Show 'Referenced Libraries' Node ”进行调节。
- 对于普通的java项目,为了工程目录结构的清爽,我们将引入的jar包放到“Referenced Libraries”中,可以通过“小三角”选择是否“Show 'Referenced Libraries' Node ”进行调节。
导入jar包
包括:spring(包括springmvc)、mybatis、mybatis-spring整合包、数据库驱动、第三方连接池、jstl、c3p0管理数据源、log4j、junit。
参考:“mybatis与springmvc整合全部jar包”目录。
本次案例共导入28个jar包。如下图所示:
2.2、web.xml配置文件(入口)
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>day63_SpringMVC_01</display-name>
<!-- 配置spring编码过滤器 -->
<filter>
<filter-name>characterEcoding</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>characterEcoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置前端控制器:DispatcherServlet -->
<servlet >
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 显示配置加载springmvc.xml文件,即配置springmvc.xml文件的初始化参数 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<!-- 配置servlet拦截扩展名 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 配置servlet拦截目录 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<!-- 配置加载spring的配置文件:beans.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value> <!-- 这两种方式均可 -->
<!-- <param-value>/WEB-INF/classes/beans.xml</param-value> -->
</context-param>
<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>
2.3、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: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交给spring管理 -->
<context:component-scan base-package="com.itheima"></context:component-scan>
<!-- 表示默认创建处理器映射器对象、处理器映射器对象,还表示默认启动json格式数据的支持 -->
<mvc:annotation-driven />
<!-- 配置jsp视图解析器,InternalResourceViewResolver负责解析出真正的逻辑视图 -->
<!-- 后台返回逻辑视图:index,jsp视图解析器解析出真正的物理视图:前缀+逻辑视图+后缀 ==>/WEB-INF/jsps/index.jsp -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsps/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
2.4、bean.xml配置文件(相当于applicationContext.xml)
bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<context:component-scan base-package=""></context:component-scan>
<!-- 1、配置数据源 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 2、配置sqlSessionFactory,用于生产sqlSession -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:sqlMapConfig.xml"></property>
</bean>
<!-- 配置mybatis的Mapper接口代理开发,需要遵循的几点规范 -->
<!--
1、mapper接口的全限定名要和mapper映射文件的namespace的值相同。
2、mapper接口的方法名称要和mapper映射文件中的statement的id相同。
3、mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
4、mapper接口的返回值类型要和mapper映射文件中statement的resultType的值或resultMap中的type的值保持一致。
5、mapper接口和mapper映射文件必须在同一目录下。
-->
<!-- mapper代理开发方式之批量mapper配置,默认bean的id为类名首字母小写 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定批量mapper配置的包名 -->
<property name="basePackage" value="com.itheima.dao"></property>
<!-- 当只有一个SqlSessionFactory时,默认是不需要配置SqlSessionFactory的 -->
<!-- 当有多个SqlSessionFactory时,可以指定使用的SqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- 3、配置事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置通知:管理事务的策略 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置拦截service:切面编程 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service.*.*(..))"/>
</aop:config>
</beans>
2.6、编写代码
mapper层(dao层):
mapper接口代码使用Mybatis的逆向工程生成的。
service层:
ItemsService.java
public interface ItemsService {
public List<Items> findAll();
public Items findById(Integer id);
public void saveOrUpdate(Items items);
public void deleteById(Integer id);
}
ItemsServiceImpl.java
@Service
public class ItemsServiceImpl implements ItemsService {
// 注入接口对象(Mapper接口使用代理类)
@Resource
private ItemsMapper itemsMapper;
public List<Items> findAll() {
List<Items> list = itemsMapper.findAll();
return list;
}
public Items findById(Integer id) {
Items items = itemsMapper.selectByPrimaryKey(id);
return items;
}
public void saveOrUpdate(Items items) {
itemsMapper.updateByPrimaryKey(items); // 商品id通过页面隐藏域传过来的
}
public void deleteById(Integer id) {
itemsMapper.deleteByPrimaryKey(id);
}
}
controller层(web层/Action层):
ItemsController.java
@Controller
@RequestMapping("/items")
public class ItemsController {
// 注入service对象
@Resource
private ItemsService itemsService;
// 查询所有商品方法
@RequestMapping("list")
// springmvc使用Model对象进行页面数据回显,Model对象相当于javaweb时所学的application对象(应用域对象),所以Model对象中的数据,在页面上可以通过EL表达式进行获取。
// 有了Model对象,才可以向对象中放值,那么Model对象该如何创建呢?
// 答:“由于springmvc中放到方法里面的对象会自动被创建”,那么我们就把Model对象放到方法里面。
public String list(Model model) {
List<Items> itemsList = itemsService.findAll();
model.addAttribute("itemsList", itemsList);
return "itemsList";
}
// 修改商品方法
@RequestMapping("editById")
public String editById(Integer id, Model model) {
// 跟据id查询商品
Items items = itemsService.findById(id);
model.addAttribute("items", items);
return "editItems";
}
// 修改后保存方法
@RequestMapping("saveOrUpdate")
public String saveOrUpdate(Items items) {
itemsService.saveOrUpdate(items); // 商品id通过页面隐藏域传过来的
return "redirect:list.do";
}
// 跟据id进行删除
@RequestMapping("deleteById")
public String deleteById(Integer id) {
itemsService.deleteById(id);
return "redirect:list.do";
}
// 跟据ids进行批量删除
@RequestMapping("deleteByIds")
public String deleteByIds(Integer[] ids) { // 特别注意:标签input的name的属性值id要与方法的形式参数名称id相同。形参名称也可以起别名!但需要其他注解配合哦!
for (Integer id : ids) {
itemsService.deleteById(id);
}
return "redirect:list.do";
}
}
2.7、springmvc文件上传
需求分析:
使用ajax,响应json格式数据的形式上传图片并立刻回显。页面不刷新图片回显立刻。
ajax能不能提交表单?
答:ajax自己不能提交表单。要想ajax提交表单,需要借助一个插件。
为什么我们要提交表单?
答:因为我们要提交一个文件对象,需要将文件对象关联到表单里面。
当我们点击一个按钮的时候,这个被关联到表单里的对象,才会被提交。
伪代码示例如下:
// 图片回显
<img src=“图片路径”/>
// 把文件关联表单,触发ajax事件
<input type="file" onchange="ajax事件"/>
<input type="hidden" value="图片相对路径"/>
// 本示例开始,我们不使用 enctype="multipart/form-data" 提交文件对象了
// 我们直接使用ajax提交文件对象,我们添加隐藏域,向后台提交图片相对路径
(1)导入跨服务器上传文件的jar包、IO、fileupload
(2)模拟2台服务器
创建一个动态的java web项目:图片服务器项目,图片服务器项目的服务器和上传图片项目的服务器端口不一致即可。如下图所示:
(3)springmvc支持文件上传,需要先在springmvc.xml配置文件中开启文件上传
在springmvc.xml配置文件中新加入的内容如下:
<!-- 配置开启文件上传,因为我们要跨服务器上传,需要写上id,该id名称固定 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 配置文件上传大小 -->
<property name="maxUploadSize" value="1024000"></property>
</bean>
(4)前台页面ajax
功能:发送请求,请求上传图片,图片需要被关联在表单里。
使用ajax提交form表单的插件:jquery.form.js
(5)后台代码
@Controller
@RequestMapping("/upload")
public class UploadController {
@RequestMapping("uploadPic")
public void uploadPic(HttpServletRequest request, String fileName, PrintWriter out) {
// 1、准备文件上传流
// 由于上传的图片在请求里面,它是流类型的,直接通过Request对象不能操作
// 所以先要把Request对象强转成多部件请求对象
MultipartHttpServletRequest mhr = (MultipartHttpServletRequest) request;
// 根据文件名称获取普通多部件文件对象
CommonsMultipartFile cmFile = (CommonsMultipartFile) mhr.getFile(fileName);
// 获取文件上传流
byte[] fbytes = cmFile.getBytes();
// 2、准备文件名称
// 文件名称在服务器有可能重复,我们使用时间来区分他们
String newFileName = "";
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
newFileName = sdf.format(new Date());
// 在毫秒的时候文件名也可能重复,我们再加点盐
Random r = new Random(); // [0,1)
for (int i = 0; i < 3; i++) {
newFileName = newFileName + r.nextInt(10);
}
// 3、获取文件扩展名
String originalFilename = cmFile.getOriginalFilename();
// int x = a.lastIndexOf(b); // 表示b字符串在a字符串中最后出现的位置,从0开始
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
// 4、创建jesy服务器,进行跨服务器上传
Client client = Client.create();
// 把文件关联到远程服务器
// 图片文件的完整路径为:http://127.0.0.1:9005/day64_SSMImageServer/upload/20181027174523998.png
WebResource resource = client.resource(Commons.PIC_HOST + "/upload/" + newFileName + suffix);
// 上传图片文件
resource.put(String.class, fbytes);
// 5、ajax回调函数需要回显什么东西呢?
// 图片需要回显:需要图片的完整路径
// 数据库保存图片:需要图片的相对路径
String fullPath = Commons.PIC_HOST + "/upload/" + newFileName + suffix;
String relativePath = "/upload/" + newFileName + suffix;
// json格式的数据:{"":"","":""}
String result = "{\"fullPath\":\"" + fullPath + "\",\"relativePath\":\"" + relativePath + "\"}";
out.print(result);
}
}
(6)修改图片服务器文件上传权限
(7)图片上传位置
(8)图片列表回显
回显图片需要使用<img/>标签
itemsList.jsp
<c:set var="picPath" value="http://127.0.0.1:9090/day64_SSMImageServer"></c:set>
......
<td>
<img id='imgSize1ImgSrc' src='${picPath}${items.pic}' height="100" width="100"/>
</td>
editItems.jsp
<c:set var="picPath" value="http://127.0.0.1:9090/day64_SSMImageServer"></c:set>
......
<img id='imgSize1ImgSrc' src='${picPath}${items.pic}' height="100" width="100"/>
......
3、页面缓存
需求:使用页面缓存来提高用户体验度。
3.1、简单理解缓存原理
简单理解缓存原理图解如下:
优点:提升性能。
缺点:不访问数据库,不是实时数据。
思考:怎么样能中和一下优缺点呢?
- 页面静态化:
- 静态化技术连缓存都不走了,直接给你一个HTML页面,缺点更大。
- 分布式缓存:
- 分布式缓存能控制`颗粒的大小`,分布式缓存使用的是redis,memcached等等
- 这相当于是数据库,因为我们在任何一层都可以进行操作数据库。所以可以进行颗粒大小的控制。
3.2、浅谈互联网架构
浅谈互联网架构图解:
3.3、实现页面缓存
使用Oscache
实现页面缓存。
(1)创建一个动态的java web项目,导入所需的jar包
(2)测试:创建一个index.jsp页面,使用时间来测试
(3)访问测试
http://localhost:8080/day64_Oscache/index.jsp
http://localhost:8080/day64_Oscache/
分析:上面2个地址都访问同一个页面,为什么缓存会变化呢?
缓存原理:
缓存数据结构:是一个map集合。
key存储的是浏览器访问的url,上面2个url不一致,缓存肯定变化。
value存储的是缓存页面的数据。
(4)缓存的存储范围
缓存默认存储在application域当中。
在不同的浏览器之间访问同一地址,缓存时间不会发生变化。
(5)改变缓存的存储范围
改变缓存的存储范围为session域中。在不同的浏览器之间访问同一地址,缓存时间会发生变化。
(6)固定缓存的key
由于固定了缓存的key,所以以下2个地址访问同一个页面,缓存时间不会发生变化。
http://localhost:8080/day64_Oscache/index.jsp
http://localhost:8080/day64_Oscache/
(7)要求每隔4秒缓存同步(刷新)一次
(8)要求缓存持久化到磁盘或者保存到redis缓存服务器中
创建oscache.properties,这个配置文件必须在classpath下面,文件内容如下:
oscache.properties
cache.memory=false // 不使用缓存内存
cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.DiskPersistenceListener // 持久化类
cache.path=E:\\oscache // 持久化到E盘oscache目录下
查看持久化文件
3.4、在SSM项目中使用Oscache
约定:假如商品页面访问量特别大,我们给商品页面使用缓存。即:约定items路径下所有请求都缓存。
(1)将oscache-2.4.1.jar拷贝至项目lib目录下,并添加至构建路径
(2)在web.xml中配置缓存过滤器
(3)测试缓存
打一个断点(给商品查询列表),第一次断点必须走,第二次断点不走,走缓存页面。
(4)配置缓存的持久化
将配置文件oscache.properties拷贝至项目的config目录下即可。
4、使用springmvc的其他视图
4.1、整合freemarker视图
- 需求:使用springmvc本身的视图解析器来解析页面静态化。
(1)导入所需要的jar包
com.springsource.freemarker-2.3.15.jar和spring-context-support-3.2.0.RELEASE.jar
(2)在springmvc.xml中配置对freemarker视图的支持
配置对freemarker视图的支持后,我们发现我们可以不使用jsp来开发了,我们可以直接使用freemarker视图来开发。
即:我们可以删除掉在springmvc.xml中配置的jsp视图解析器了。
(3)编写freemarker的页面
WebRoot/WEB-INF/jsps/ftl.ftl
(4)编写后台代码
@Controller
@RequestMapping("/ftl")
public class FtlController {
@RequestMapping("hello")
public String hello(Model model) {
model.addAttribute("hello","页面静态化技术之freemarker");
return "ftl";
}
}
(5)修改itemsList.jsp页面为静态化页面itemsList.ftl
itemsList.ftl
<#assign picPath="http://127.0.0.1:9090/day64_SSMImageServer"/>
<#assign projectName="day64_SpringMVC_02"/>
<!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="${projectName}/items/deleteByIds.do" method="post">
查询条件:
<table width="100%" border=1>
<tr>
<td><input type="submit" value="查询"/></td>
<td><input type="submit" value="批量删除"/></td>
</tr>
</table>
商品列表:
<table width="100%" border=1>
<tr>
<td>商品ID</td>
<td>商品名称</td>
<td>商品图片</td>
<td>商品价格</td>
<td>生产日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<#list itemsList as items>
<tr>
<!-- 添加复选框 -->
<td><!-- 特别注意:标签input的name的属性值id要与方法的形式参数名称id相同。 -->
<input type="checkbox" name="ids" value="${items.id}"><!-- 复选框中的值需要提交表单才能传递给后台 -->
</td>
<td>${items.name}</td>
<td>
<img id='imgSize1ImgSrc' src='${picPath}${items.pic}' height="100" width="100"/>
</td>
<td>${items.price}</td>
<td>${items.detail}</td>
<td>
<a href="${projectName}/items/editById.do?id=${items.id}">修改</a>
<a href="${projectName}/items/deleteById.do?id=${items.id}">删除</a>
</td>
</tr>
</#list>
</table>
</form>
</body>
</html>
(6)访问测试
访问地址:http://localhost:8080/day64_SpringMVC_02/items/list.do
访问测试没有问题,以上演示就是springmvc对freemarker的支持。
5、拦截器
定义:
Spring Web MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
5.1、局部拦截器
针对某个HandlerMapping进行配置,只对当前HandlerMapping有效。即针对单个处理器映射器,称为局部拦截器。
在springmvc.xml中的配置示例如下:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="handlerInterceptor1"/>
<ref bean="handlerInterceptor2"/>
</list>
</property>
</bean>
<bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
<bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>
拦截器代码编写:需要实现HandlerInterceptor接口
public class HandlerInterceptor1 implements HandlerInterceptor {
/**
* controller执行前调用此方法
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
return false;
}
/**
* controller执行后但未返回视图前调用此方法
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
}
/**
* controller执行后且视图返回后调用此方法
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
}
5.2、全局拦截器
拦截所有请求。
在springmvc.xml中的配置示例如下:
<!--配置全局拦截器 -->
<mvc:interceptors>
<!--配置多个拦截器,顺序执行 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itheima.interceptor.HandlerInterceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itheima.interceptor.HandlerInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器代码编写:需要实现HandlerInterceptor接口
HandlerInterceptor1.java
// 拦截器代码编写:需要实现HandlerInterceptor接口
public class HandlerInterceptor1 implements HandlerInterceptor {
/**
* controller执行前调用此方法,即在处理器映射器之前执行
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
System.out.println("这是第1个拦截器的preHandle()方法");
return false;
}
/**
* controller执行后但未返回视图前调用此方法,即调用Controller了,还没返回ModelAndView执行
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("这是第1个拦截器的postHandle()方法");
}
/**
* controller执行后且视图返回后调用此方法,即返回ModelAndView之后执行
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("这是第1个拦截器的afterCompletion()方法");
}
HandlerInterceptor2.java
// 拦截器代码编写:需要实现HandlerInterceptor接口
public class HandlerInterceptor2 implements HandlerInterceptor {
/**
* controller执行前调用此方法
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
System.out.println("这是第2个拦截器的preHandle()方法");
return false;
}
/**
* controller执行后但未返回视图前调用此方法
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("这是第2个拦截器的postHandle()方法");
}
/**
* controller执行后且视图返回后调用此方法
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("这是第2个拦截器的afterCompletion()方法");
}
5.3、测试
(1)第1个拦截器放行,第2个拦截器也放行。
即两个拦截器的preHandle()方法都返回true。
测试结果如下:
这是第1个拦截器的preHandle()方法
这是第2个拦截器的preHandle()方法
这是第2个拦截器的postHandle()方法
这是第1个拦截器的postHandle()方法
这是第2个拦截器的afterCompletion()方法
这是第1个拦截器的afterCompletion()方法
(2)第1个拦截器放行,第2个拦截器不放行。
即第一个拦截器的preHandle()方法返回true,第二个拦截器的preHandle()方法返回false。
springmvc规定:凡是方法preHandle()返回true,则方法afterCompletion()必须执行。
测试结果如下:
这是第1个拦截器的preHandle()方法
这是第2个拦截器的preHandle()方法
这是第1个拦截器的afterCompletion()方法
(3)第1个拦截器不放行,第2个拦截器不放行。
即两个拦截器的preHandle()方法都返回false。
测试结果如下:
这是第1个拦截器的preHandle()方法
5.4、拦截器应用:用户身份认证
示例代码如下:
public class LoginInterceptor implements HandlerInterceptor{
/**
* controller执行前调用此方法,即在处理器映射器之前执行
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 如果是登录页面则放行
if (request.getRequestURI().indexOf("login.action") >= 0) {
return true; // 放行
}
HttpSession session = request.getSession();
// 如果用户已登录也放行
if (session.getAttribute("user") != null) {
return true; // 放行
}
// 用户没有登录跳转到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false; // 不放行
}
/**
* controller执行后但未返回视图前调用此方法,即调用Controller了,还没返回ModelAndView执行
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
}
/**
* controller执行后且视图返回后调用此方法,即返回ModelAndView之后执行
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
}