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>
                        <href="${projectName}/items/editById.do?id=${items.id}">修改</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 {
    }
}

posted on 2018-12-04 22:26  pony1223  阅读(421)  评论(0编辑  收藏  举报

导航