• day64_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设置为 WebRootWEB-INFclasses
    • 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 
    {
        }
    }

    6、springmvc整合Hibernate

    未完待续……

  • 相关阅读:
    暴力字符串hash——cf1200E
    单调栈+线段树——cf1220F
    拆边+BFS队列骚操作——cf1209F
    控制器
    linux下安装配置jmeter
    docker-compose.yml配置jforum开源系统
    anyproxy
    docker搭建一键安装包lnmp
    docker tomcat,mysql 搭建开源项目jforum
    接口自动化测试-Mock Get和Post请求
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/9866325.html
Copyright © 2020-2023  润新知