Java Maven+Idea 構(gòu)建SpringMvc+Mybatis項(xiàng)目

  • 本文將使用maven與Idea創(chuàng)建一個(gè)Springmvc+Mybatis+Ehcache的空項(xiàng)目
  • 本文全部代碼
  • mvn命令行創(chuàng)建項(xiàng)目基本結(jié)構(gòu)
mvn archetype:generate -DgroupId=com.mico.emptyspring -DartifactId=emptyspring -DarchetypeArtifactId=maven-archetype-webapp -DinteractivMode=false
  • 使用idea打開(kāi)項(xiàng)目
  • 修改pom.xml,定義源碼版本和編譯的class版本,否則maven有個(gè)默認(rèn)的編譯版本岸裙,可能較低
<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
</properties>
  ......
<build>
        <finalName>emptyspring</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                        <encoding>${project.build.sourceEncoding}</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
</build>
  • src/main目錄下創(chuàng)建java文件夾猖败,標(biāo)記為Source root

    Sources

  • 在java文件夾下創(chuàng)建包名


    大概像這樣
  • 添加spring依賴到pom.xml

        <!-- 基本包 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>

        <!-- 文件上傳解析 -->
        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>

        <!--JDBC-->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>



        <!-- jackson -->
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.7</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.7</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.7</version>
        </dependency>



        <!-- 日志文件管理包 -->
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>1.7.22</version>
        </dependency>
        <!--slf4j-log4j12 代表綁定的是log4j 1.2版本-->
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.7.22</version>
        </dependency>
        <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
        </dependency>



         <!--核心包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--webmvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--context-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!-- context-support EhCacheManagerFactoryBean 在這里 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--事物-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--orm-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <!-- mybatis -->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

        <!-- 分頁(yè)插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.8</version>
        </dependency>
        <!-- mybatis ehcache -->
        <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.1.0</version>
        </dependency>
  • 編輯web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:spring-*.xml
        </param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <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>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>

    </servlet>
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>


    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>
  • 在resource文件夾下新加spring-mvc.xml[掃描控制層,配置靜態(tài)資源降允,消息轉(zhuǎn)換器恩闻,視圖解析器]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 配置自動(dòng)掃描的包 -->
    <!--<task:annotation-driven/>-->
    <mvc:annotation-driven/>
    <context:component-scan base-package="com.mico.emptyspring.controller"/>


    <!-- 加載properties配置文件 -->
    <context:property-placeholder location="classpath:*.properties"/>


    <!-- 處理靜態(tài)資源 -->
    <!-- <mvc:default-servlet-handler/>  -->
    <!--<mvc:resources mapping="/*.jsp" location="/"/>-->
    <!--<mvc:resources mapping="/*.html" location="/"/>-->
    <!--<mvc:resources mapping="/*.ico" location="/"/>-->
    <mvc:resources mapping="/js/**" location="/js/"/>
    <mvc:resources mapping="/css/**" location="/css/"/>

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/static/**"/>
            <mvc:exclude-mapping path="/*.html"/>
            <mvc:exclude-mapping path="/favicon.ico"/>
            <bean class="com.mico.emptyspring.interceptor.CommonInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="com.mico.emptyspring.convert.MessageConverter"></bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
        <!-- set the max upload size100MB -->
        <property name="maxUploadSize">
            <value>104857600</value>
        </property>
        <property name="maxInMemorySize">
            <value>4096</value>
        </property>
        <property name="defaultEncoding" value="UTF-8"></property>
    </bean>

     <!--配置視圖解析器: 如何把 handler 方法返回值解析為實(shí)際的物理視圖

        如果方法不標(biāo)示為@ResponseBody,將會(huì)走視圖解析器拟糕,也不會(huì)走消息轉(zhuǎn)換器[將對(duì)象轉(zhuǎn)為json字符串]判呕,

        @responseBody注解的作用是將controller的方法返回的對(duì)象通過(guò)適當(dāng)?shù)霓D(zhuǎn)換器轉(zhuǎn)換為指定的格式之后,
        寫(xiě)入到response對(duì)象的body區(qū)送滞,通常用來(lái)返回JSON數(shù)據(jù)或者是XML數(shù)據(jù)侠草,需要注意的呢,
        在使用此注解之后不會(huì)再走視圖處理器犁嗅,而是直接將數(shù)據(jù)寫(xiě)入到輸入流中边涕,
        他的效果等同于通過(guò)response對(duì)象輸出指定格式的數(shù)據(jù)。@ResponseBody都會(huì)在異步獲取數(shù)據(jù)時(shí)使用,
        被其標(biāo)注的處理方法返回的數(shù)據(jù)將輸出到相應(yīng)流中,客戶端獲取并顯示數(shù)據(jù)褂微。
     -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>
  • 新增spring-mybatis.xml 整合spirng和mybatis
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd


        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- Mybatis 和 Spring的整合 -->

    <!-- 自動(dòng)掃描 ,忽略@Controller注解的類-->
    <context:component-scan base-package="com.mico.emptyspring">
        <context:exclude-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"></context:exclude-filter>
    </context:component-scan>

    <!-- 1.數(shù)據(jù)源:DriverManagerDataSource -->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="micocube"></property>
    </bean>

    <!-- 2.Mybatis 的 SqlSession的工廠:SqlSessionFactoryBean dataSource引用數(shù)據(jù)源 Mybatis
        定義數(shù)據(jù)源功蜓,同意加載配置 -->
    <!--<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">-->
    <!--<property name="dataSource" ref="dataSource"></property>-->
    <!--<property name="configLocation" value="classpath:mybatis-config.xml"></property>-->
    <!--</bean>-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--<property name="mapperLocations" value="classpath:mappers/*.xml"/>-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- <property name="typeAliasesPackage" value="com.tiantian.ckeditor.model" /> -->
    </bean>


    <!-- 3. Mybatis自動(dòng)掃描加載Sql映射文件/接口:MapperScannerConfigurer sqlSessionFactory
        basePackage:指定sql映射文件/接口所在的包(自動(dòng)掃描) -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.mico.emptyspring.dao"></property>
        <!-- 一直不明白為什么sqlSessionFactoryBeanName要用value而不用ref.
        在mybatis-spring1.1.0以前,是通過(guò)<property name="sqlSessionFactory" r
        ef="sqlSessionFactory"/>將SqlSessionFactory對(duì)象注入到sqlSessionFactory宠蚂,
        這樣做可能會(huì)有一個(gè)問(wèn)題式撼,就是在初始化MyBatis時(shí),jdbc.properties文件還沒(méi)被加載進(jìn)來(lái)求厕,
        dataSource的屬性值沒(méi)有被替換著隆,就開(kāi)始構(gòu)造sqlSessionFactory類,屬性值就會(huì)加載失敗呀癣。
        在1.1.0以后美浦,MapperScannerConfigure提供了String類型的sqlSessionFactoryBeanName,
        這樣將bean name注入到sqlSessionFactoryBeanName项栏,這樣就會(huì)等到spring初始化完成后浦辨,
        再構(gòu)建sqlSessionFactory。-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>


    <!-- 4.事務(wù)管理:DataSourceTransactionManager dataSource 引用上面定義好的數(shù)據(jù)源 -->
    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


    <!-- 5.使用聲明式事務(wù): transaction-manager = "txManager" tx:advice 這種 是用 aop方式管理事物
        annotation-driven 這種是注解方式管理事物 第一種方式沼沈,需要在spring配置文件配置一些參數(shù) 第二種方式流酬,需要在 類里 加一些注解進(jìn)行事物管理用一種就行,沒(méi)必須都用 -->
    <tx:annotation-driven transaction-manager="txManager"/>
</beans>
  • 新增mybatis-config.xml,對(duì)mybatis進(jìn)行配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- mybatis 配置文件文檔 http://www.mybatis.org/mybatis-3/zh/configuration.html -->

    <!-- 全局參數(shù) Mappers文件里可以重寫(xiě)列另,查看UserMapper.xml-->
    <settings>
        <!-- 配置打印 SQL 到控制臺(tái) -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!-- 全局地開(kāi)啟或關(guān)閉配置文件中的所有映射器已經(jīng)配置的任何緩存康吵。 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 全局啟用或禁用延遲加載。當(dāng)禁用時(shí)访递,所有關(guān)聯(lián)對(duì)象都會(huì)即時(shí)加載晦嵌。 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 當(dāng)啟用時(shí),有延遲加載屬性的對(duì)象在被調(diào)用時(shí)將會(huì)完全加載任意屬性。否則惭载,每種屬性將會(huì)按需要加載旱函。 -->
        <setting name="aggressiveLazyLoading" value="true"/>
        <!-- 是否允許單條sql 返回多個(gè)數(shù)據(jù)集  (取決于驅(qū)動(dòng)的兼容性) default:true -->
        <setting name="multipleResultSetsEnabled" value="true"/>
        <!-- 是否可以使用列的別名 (取決于驅(qū)動(dòng)的兼容性) default:true -->
        <setting name="useColumnLabel" value="true"/>
        <!-- 允許JDBC 生成主鍵。需要驅(qū)動(dòng)器支持描滔。如果設(shè)為了true棒妨,這個(gè)設(shè)置將強(qiáng)制使用被生成的主鍵,有一些驅(qū)動(dòng)器不兼容不過(guò)仍然可以執(zhí)行含长。  default:false  -->
        <setting name="useGeneratedKeys" value="true"/>
        <!-- 指定 MyBatis 如何自動(dòng)映射 數(shù)據(jù)基表的列 NONE:不隱射 PARTIAL:部分  FULL:全部  -->
        <setting name="autoMappingBehavior" value="PARTIAL"/>
        <!-- 這是默認(rèn)的執(zhí)行類型  (SIMPLE: 簡(jiǎn)單券腔; REUSE: 執(zhí)行器可能重復(fù)使用prepared statements語(yǔ)句;BATCH: 執(zhí)行器可以重復(fù)執(zhí)行語(yǔ)句和批量更新)  -->
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <!-- 使用駝峰命名法轉(zhuǎn)換字段拘泞。 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 設(shè)置本地緩存范圍 session:就會(huì)有數(shù)據(jù)的共享  statement:語(yǔ)句范圍 (這樣就不會(huì)有數(shù)據(jù)的共享 ) defalut:session -->
        <setting name="localCacheScope" value="SESSION"/>
        <!-- 設(shè)置但JDBC類型為空時(shí),某些驅(qū)動(dòng)程序 要指定值,default:OTHER纷纫,插入空值時(shí)不需要指定類型 -->
        <setting name="jdbcTypeForNull" value="NULL"/>
    </settings>


    <!--設(shè)置一個(gè)別名 -->
    <typeAliases>
        <typeAlias type="com.mico.emptyspring.entity.User" alias="User"/>
    </typeAliases>

    <!-- 啟用pageHelper插件 在代碼中使用
    Page page = PageHelper.startPage(pageNum, pageSize, true);在查詢前使用
    true表示需要統(tǒng)計(jì)總數(shù),這樣會(huì)多進(jìn)行一次請(qǐng)求select count(0); 省略掉true參數(shù)只返回分頁(yè)數(shù)據(jù)陪腌。

    1.統(tǒng)計(jì)總數(shù)辱魁,(將SQL語(yǔ)句變?yōu)?select count(0) from xxx,只對(duì)簡(jiǎn)單SQL語(yǔ)句其效果,復(fù)雜SQL語(yǔ)句需要自己寫(xiě))
        Page<?> page = PageHelper.startPage(1,-1);
        long count = page.getTotal();


    2.分頁(yè)诗鸭,pageNum - 第N頁(yè)染簇, pageSize - 每頁(yè)M條數(shù)
        2.1只分頁(yè)不統(tǒng)計(jì)(每次只執(zhí)行分頁(yè)語(yǔ)句)
            PageHelper.startPage([pageNum],[pageSize]);
            List<?> pagelist = queryForList( xxx.class, "queryAll" , param);
            //pagelist就是分頁(yè)之后的結(jié)果
        2.2 分頁(yè)并統(tǒng)計(jì)(每次執(zhí)行2條語(yǔ)句,一條select count語(yǔ)句强岸,一條分頁(yè)語(yǔ)句)
            適用于查詢分頁(yè)時(shí)數(shù)據(jù)發(fā)生變動(dòng)锻弓,需要將實(shí)時(shí)的變動(dòng)信息反映到分頁(yè)結(jié)果上
            Page<?> page = PageHelper.startPage([pageNum],[pageSize],[iscount]);
            List<?> pagelist = queryForList( xxx.class , "queryAll" , param);
            long count = page.getTotal();
            也可以 List<?> pagelist = page.getList();  獲取分頁(yè)后的結(jié)果集


    3.使用PageHelper查全部(不分頁(yè))
        PageHelper.startPage(1,0);
        List<?> alllist = queryForList( xxx.class , "queryAll" , param);

    4.PageHelper的其他API
        //獲取orderBy語(yǔ)句
        String orderBy = PageHelper.getOrderBy();
        Page<?> page = PageHelper.startPage(Object params);
        Page<?> page = PageHelper.startPage(int pageNum, int pageSize);
        Page<?> page = PageHelper.startPage(int pageNum, int pageSize, boolean isCount);
        Page<?> page = PageHelper.startPage(pageNum, pageSize, orderBy);
        //isReasonable分頁(yè)合理化,null時(shí)用默認(rèn)配置
        Page<?> page = PageHelper.startPage(pageNum, pageSize, isCount, isReasonable);
        //isPageSizeZero是否支持PageSize為0,true且pageSize=0時(shí)返回全部結(jié)果蝌箍,false時(shí)分頁(yè),null時(shí)用默認(rèn)配置
        Page<?> page = PageHelper.startPage(pageNum, pageSize, isCount, isReasonable, isPageSizeZero);

    5.默認(rèn)值
        //RowBounds參數(shù)offset作為PageNum使用 - 默認(rèn)不使用
        private boolean offsetAsPageNum = false;
        //RowBounds是否進(jìn)行count查詢 - 默認(rèn)不查詢
        private boolean rowBoundsWithCount = false;
        //當(dāng)設(shè)置為true的時(shí)候青灼,如果pagesize設(shè)置為0(或RowBounds的limit=0),就不執(zhí)行分頁(yè)十绑,返回全部結(jié)果
        private boolean pageSizeZero = false;
        //分頁(yè)合理化
        private boolean reasonable = false;
        //是否支持接口參數(shù)來(lái)傳遞分頁(yè)參數(shù)聚至,默認(rèn)false
        private boolean supportMethodsArguments = false;

    6.有一個(gè)安全性問(wèn)題酷勺,需要注意一下本橙,不然可能導(dǎo)致分頁(yè)錯(cuò)亂
        什么時(shí)候會(huì)導(dǎo)致不安全的分頁(yè)?
        PageHelper 方法使用了靜態(tài)的 ThreadLocal 參數(shù)脆诉,分頁(yè)參數(shù)和線程是綁定的甚亭。
        只要你可以保證在 PageHelper 方法調(diào)用后緊跟 MyBatis 查詢方法,這就是安全的击胜。因?yàn)?PageHelper 在 finally 代碼段中自動(dòng)清除了 ThreadLocal 存儲(chǔ)的對(duì)象亏狰。
        如果代碼在進(jìn)入 Executor 前發(fā)生異常,就會(huì)導(dǎo)致線程不可用偶摔,這屬于人為的 Bug(例如接口方法和 XML 中的不匹配暇唾,導(dǎo)致找不到 MappedStatement 時(shí)), 這種情況由于線程不可用,也不會(huì)導(dǎo)致 ThreadLocal 參數(shù)被錯(cuò)誤的使用策州。
        但是如果你寫(xiě)出下面這樣的代碼瘸味,就是不安全的用法:

        PageHelper.startPage(1, 10);
        List<Country> list;
        if(param1 != null){
            list = countryMapper.selectIf(param1);
        } else {
            list = new ArrayList<Country>();
        }

        這種情況下由于 param1 存在 null 的情況,就會(huì)導(dǎo)致 PageHelper 生產(chǎn)了一個(gè)分頁(yè)參數(shù)够挂,但是沒(méi)有被消費(fèi)旁仿,這個(gè)參數(shù)就會(huì)一直保留在這個(gè)線程上。當(dāng)這個(gè)線程再次被使用時(shí)孽糖,就可能導(dǎo)致不該分頁(yè)的方法去消費(fèi)這個(gè)分頁(yè)參數(shù)枯冈,這就產(chǎn)生了莫名其妙的分頁(yè)。
        上面這個(gè)代碼办悟,應(yīng)該寫(xiě)成下面這個(gè)樣子:

        List<Country> list;
        if(param1 != null){
            PageHelper.startPage(1, 10);
            list = countryMapper.selectIf(param1);
        } else {
            list = new ArrayList<Country>();
        }

        這種寫(xiě)法就能保證安全尘奏。
        如果你對(duì)此不放心,你可以手動(dòng)清理 ThreadLocal 存儲(chǔ)的分頁(yè)參數(shù)誉尖,可以像下面這樣使用:

        List<Country> list;
        if(param1 != null){
            PageHelper.startPage(1, 10);
            try{
                list = countryMapper.selectAll();
            } finally {
                PageHelper.clearPage();
            }
        } else {
            list = new ArrayList<Country>();
        }

        這么寫(xiě)很不好看罪既,而且沒(méi)有必要。

    PageHelper的優(yōu)點(diǎn)是铡恕,分頁(yè)和Mapper.xml完全解耦琢感。實(shí)現(xiàn)方式是以插件的形式,
    對(duì)Mybatis執(zhí)行的流程進(jìn)行了強(qiáng)化探熔,添加了總數(shù)count和limit查詢驹针。屬于物理分頁(yè)。
    5.0 是用這個(gè)類
    com.github.pagehelper.PageInterceptor
    因?yàn)镻ageHelper類诀艰,繼承Interceptor
    public class PageHelper extends PageMethod implements Dialect
    -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--自4.0.0以后的版本已經(jīng)可以自動(dòng)識(shí)別數(shù)據(jù)庫(kù)了柬甥,所以不需要我們?cè)偃ブ付〝?shù)據(jù)庫(kù)-->
            <!--<property name="dialect" value="mysql"/>-->
            <!--<property name="offsetAsPageNum" value="false"/>-->
            <!--<property name="rowBoundsWithCount" value="false"/>-->
            <!--<property name="pageSizeZero" value="true"/>-->
            <!--<property name="reasonable" value="false"/>-->
            <!--<property name="supportMethodsArguments" value="false"/>-->
            <!--<property name="returnPageInfo" value="none"/>-->
        </plugin>
    </plugins>

    <mappers>
        <package name="com.mico.emptyspring.dao"></package>
    </mappers>
</configuration>
  • 新增spring-ehcache.xml,整合spring和ehcache
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/cache
        http://www.springframework.org/schema/cache/spring-cache.xsd">


    <!-- 啟用緩存注解功能,這個(gè)是必須的其垄,否則注解不會(huì)生效苛蒲,另外,該注解一定要聲明在spring主配置文件中才會(huì)生效 -->
    <cache:annotation-driven cache-manager="ehcacheManager"/>
    <!-- cacheManager工廠類绿满,指定ehcache.xml的位置 -->
    <bean id="ehcacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache.xml"/>
    </bean>
    <!-- 聲明cacheManager -->
    <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager" ref="ehcacheManagerFactory"/>
    </bean>
</beans>
  • 編寫(xiě)ehcache.xml,配置ehcache
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <!--添加updateCheck="false"臂外,不添加會(huì)報(bào)錯(cuò)-->
    <!--[DEBUG-console] 2019/01/28,15:08:07.253|Update check failed:-->
    <!--java.io.IOException: Server returned HTTP response code: 403 for URL: http://www.terracotta.org/kit/reflector?pageID=update.properties&kitID=ehcache.default&id=-1407972861&os-name=Mac+OS+X&jvm-name=Java+HotSpot%28TM%29+64-Bit+Server+VM&jvm-version=1.8.0_131&platform=x86_64&tc-version=2.6.11&tc-product=Ehcache+Core+2.6.11&source=Ehcache+Core&uptime-secs=1&patch=UNKNOWN-->


    <!--
     屬性說(shuō)明:
        ? diskStore:指定數(shù)據(jù)在磁盤(pán)中的存儲(chǔ)位置。
        ? defaultCache:當(dāng)借助CacheManager.add("demoCache")創(chuàng)建Cache時(shí)喇颁,EhCache便會(huì)采用<defalutCache/>指定的的管理策略
        以下屬性是必須的:
            ? maxElementsInMemory - 在內(nèi)存中緩存的element的最大數(shù)目
            ? maxElementsOnDisk - 在磁盤(pán)上緩存的element的最大數(shù)目漏健,若是0表示無(wú)窮大
            ? eternal - 設(shè)定緩存的elements是否永遠(yuǎn)不過(guò)期。如果為true橘霎,則緩存的數(shù)據(jù)始終有效蔫浆,
                    如果為false那么還要根據(jù)timeToIdleSeconds,timeToLiveSeconds判斷
            ? overflowToDisk - 設(shè)定當(dāng)內(nèi)存緩存溢出的時(shí)候是否將過(guò)期的element緩存到磁盤(pán)上
            以下屬性是可選的:
            ? timeToIdleSeconds - 當(dāng)緩存在EhCache中的數(shù)據(jù)前后兩次訪問(wèn)的時(shí)間超過(guò)timeToIdleSeconds的屬性取值時(shí)姐叁,
                這些數(shù)據(jù)便會(huì)刪除瓦盛,默認(rèn)值是0,也就是可閑置時(shí)間無(wú)窮大
            ? timeToLiveSeconds - 緩存element的有效生命期洗显,默認(rèn)是0.,也就是element存活時(shí)間無(wú)窮大
            diskSpoolBufferSizeMB 這個(gè)參數(shù)設(shè)置DiskStore(磁盤(pán)緩存)的緩存區(qū)大小.默認(rèn)是30MB.每個(gè)Cache都應(yīng)該有自己的一個(gè)緩沖區(qū).
            ? diskPersistent - 在VM重啟的時(shí)候是否啟用磁盤(pán)保存EhCache中的數(shù)據(jù),默認(rèn)是false原环。
            ? diskExpiryThreadIntervalSeconds - 磁盤(pán)緩存的清理線程運(yùn)行間隔墙懂,默認(rèn)是120秒。
                每個(gè)120s扮念,相應(yīng)的線程會(huì)進(jìn)行一次EhCache中數(shù)據(jù)的清理工作
            ? memoryStoreEvictionPolicy - 當(dāng)內(nèi)存緩存達(dá)到最大损搬,有新的element加入的時(shí)候辆雾,
                移除緩存中element的策略嗤锉。默認(rèn)是LRU(最近最少使用)邮屁,可選的有LFU(最不常使用)和FIFO(先進(jìn)先出)
     -->
    <diskStore path="/data/ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>

    <cache name="baseCache" eternal="true" maxElementsInMemory="1000" maxElementsOnDisk="10000"
           overflowToDisk="true" diskPersistent="false" timeToIdleSeconds="0"
           timeToLiveSeconds="300" memoryStoreEvictionPolicy="LRU"/>

</ehcache>
  • 編寫(xiě)log4j.properties,日志配置文件
log4j.rootLogger=DEBUG,file,stdout
#log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
#log4j.appender.stdout.layout.ConversionPattern=[%p-server] %d{yyyy/MM/dd,HH:mm:ss.SSS}|%m%n
#log4j.appender.stdout.Threshold=debug
### 輸出到日志文件 ###
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=/data/www/file/logs/mico/server.log
log4j.appender.file.Append=true
log4j.appender.file.com.coding=INFO
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p-server] %d{yyyy/MM/dd,HH:mm:ss.SSS}|%m%n
#
#log4j.logger.java.sql.Statement = debug
#log4j.logger.java.sql.PreparedStatement = debug
#log4j.logger.java.sql.ResultSet =debug
#log4j.logger.java.sql.Connection =debug
#log4j.logger.com.ibatis =debug
#
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.java.sql.Statement = info
#log4j.appender.stdout.java.sql.PreparedStatement = debug
#log4j.appender.stdout.java.sql.ResultSet =debug
#log4j.appender.stdout.java.sql.Connection =debug
log4j.appender.stdout.com.coding=debug
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%p-console] %d{yyyy/MM/dd,HH:mm:ss.SSS}|%m%n
  • 編寫(xiě)攔截器記錄請(qǐng)求參數(shù)募逞,請(qǐng)求地址箱舞,請(qǐng)求ip卜范,計(jì)算請(qǐng)求處理時(shí)間
package com.mico.emptyspring.interceptor;


import com.mico.emptyspring.http.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

public class CommonInterceptor implements HandlerInterceptor {

    private static Logger log = LoggerFactory.getLogger(CommonInterceptor.class);

    public CommonInterceptor() {
        super();
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setHeader("Access-Control-Allow-Origin", "*");
        request.setAttribute(SpringMVCConstant.PROCESS_START, System.currentTimeMillis());
        Map params = new HashMap();
        request.getParameterMap().keySet().forEach(key -> {
            params.put(key, request.getParameterMap().get(key));
        });
        request.setAttribute(SpringMVCConstant.REQUEST_PARAMS, params);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception {
        if (exception == null) {
            LogContent lc = new LogContent(
                    System.currentTimeMillis() - (Long) request.getAttribute(SpringMVCConstant.PROCESS_START) + "ms",
                    request.getAttribute(SpringMVCConstant.REQUEST_PARAMS),
                    request.getAttribute(SpringMVCConstant.RESULT_FOR_LOG),
                    request.getServletPath(),
                    SpringMVCContext.getIp(request));
            String logContent = GlobalObject.getJsonMapper().writeValueAsString(lc);
            log.info(logContent);
        } else {
            LogContentWithException lc = new LogContentWithException(
                    System.currentTimeMillis() - (Long) request.getAttribute(SpringMVCConstant.PROCESS_START) + "ms",
                    request.getAttribute(SpringMVCConstant.REQUEST_PARAMS),
                    request.getAttribute(SpringMVCConstant.RESULT_FOR_LOG),
                    request.getServletPath(),
                    SpringMVCContext.getIp(request),
                    exception);
            String logContent = GlobalObject.getJsonMapper().writeValueAsString(lc);
            log.error(logContent, exception);

            GlobalObject.getJsonMapper().writeValue(response.getOutputStream(), new HttpResult(HttpStatus.SERVER_FAIL));
            response.getOutputStream().close();
        }
    }


    private class LogContent {
        public String consumed;
        public Object params;
        public Object result;
        public String url;
        public String ip;

        public LogContent(String consumed, Object params, Object result, String url, String ip) {
            this.consumed = consumed;
            this.params = params;
            this.result = result;
            this.url = url;
            this.ip = ip;
        }
    }

    private class LogContentWithException extends LogContent {
        public String throwable;

        public LogContentWithException(String consumed, Object params, Object result, String url, String ip, Exception throwable) {
            super(consumed, params, result, url, ip);
            this.throwable = throwable.toString();
        }
    }


}

  • 編寫(xiě)消息轉(zhuǎn)換器[@ResponseBody后才選擇消息轉(zhuǎn)換器]
package com.mico.emptyspring.convert;

import com.mico.emptyspring.http.GlobalObject;
import com.mico.emptyspring.http.SpringMVCConstant;
import com.mico.emptyspring.http.SpringMVCContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
 * @auther coding on 2018/3/9.
 * email: ldscube@gmail.com
 */
public class MessageConverter extends AbstractHttpMessageConverter {
    private static final Log log = LogFactory.getLog(MessageConverter.class);
    private List supportedMediaTypes = Collections.singletonList(MediaType.APPLICATION_JSON_UTF8);


    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return supportedMediaTypes;
    }

    @Override
    protected Object readInternal(Class aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }


    @Override
    protected void writeInternal(Object o, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
        log.info("writeInternal:"+o.toString());
        SpringMVCContext.getRequest().setAttribute(SpringMVCConstant.RESULT_FOR_LOG, o);
        GlobalObject.getJsonMapper().writeValue(httpOutputMessage.getBody(), o);
    }

    @Override
    protected boolean supports(Class aClass) {
        return true;
    }

}
  • 創(chuàng)建數(shù)據(jù)表
create table role
(
  id int auto_increment
    primary key,
  name varchar(255) null
)
;

create table user
(
  id int auto_increment
    primary key,
  username varchar(20) null,
  password varchar(526) null
)
;

create table user_roles
(
  user_id int not null,
  roles_id int not null
)
;

create index FK55itppkw3i07do3h7qoclqd4k
  on user_roles (user_id)
;

create index FKj9553ass9uctjrmh0gkqsmv0d
  on user_roles (roles_id)
;


INSERT INTO test.role (id,name) VALUES (1,'User');
INSERT INTO test.user (id,username, password) VALUES (1,'root', '$2a$10$TeayMIrpuDwrpLHL5QsNpOcPeE/Kx3c4UYbi4NQzNkfKgf9YtL6F2');
INSERT INTO test.user_roles (user_id, roles_id) VALUES (1, 1);
java -jar ./src/main/resources/utils/mybatis-generator-core-1.3.7.jar -configfile ./src/main/resources/mybatis-generator.xml -overwrite
  • 生成的UserMapper如下所示
package com.mico.emptyspring.dao;

import com.mico.emptyspring.entity.User;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.type.JdbcType;

import java.util.List;

public interface UserMapper {
    @Delete({
            "delete from user",
            "where id = #{id,jdbcType=INTEGER}"
    })
    int deleteByPrimaryKey(Integer id);

    @Insert({
            "insert into user (id, username, ",
            "password)",
            "values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, ",
            "#{password,jdbcType=VARCHAR})"
    })
    int insert(User record);

    @Select({
            "select",
            "id, username, password",
            "from user",
            "where id = #{id,jdbcType=INTEGER}"
    })
    @Results({
            @Result(column = "id", property = "id", jdbcType = JdbcType.INTEGER, id = true),
            @Result(column = "username", property = "username", jdbcType = JdbcType.VARCHAR),
            @Result(column = "password", property = "password", jdbcType = JdbcType.VARCHAR)
    })
    User selectByPrimaryKey(Integer id);

    @Select({
            "select",
            "id, username, password",
            "from user"
    })
    @Results({
            @Result(column = "id", property = "id", jdbcType = JdbcType.INTEGER, id = true),
            @Result(column = "username", property = "username", jdbcType = JdbcType.VARCHAR),
            @Result(column = "password", property = "password", jdbcType = JdbcType.VARCHAR)
    })
    List<User> selectAll();
    @Update({
            "update user",
            "set username = #{username,jdbcType=VARCHAR},",
            "password = #{password,jdbcType=VARCHAR}",
            "where id = #{id,jdbcType=INTEGER}"
    })
    int updateByPrimaryKey(User record);
}
  • 該操作生成6個(gè)java文件:


    mybatis-generator
  • 創(chuàng)建UserService接口
package com.mico.emptyspring.service;


import com.mico.emptyspring.entity.User;

public interface UserProcessService {
     boolean login(User user);
     User findByUserId(User u);
}

  • 創(chuàng)建UserService實(shí)現(xiàn)
package com.mico.emptyspring.service;

import com.mico.emptyspring.dao.UserMapper;
import com.mico.emptyspring.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@Transactional(rollbackFor = Exception.class)
public class UserProcessServiceImpl implements UserProcessService {

    @Autowired
    private UserMapper userDao;


    public boolean login(User userParam) {
//      Page page = PageHelper.startPage(pageNum, pageSize, true);
        User user = findByUserId(userParam);
        boolean loginSuccess = user == null ? false : true;
        return loginSuccess;
    }

    /**
     * Cacheable 會(huì)緩存方法的返回值嘀粱,
     *
     * @param u
     * @return
     *
     */

//    @Cacheable(value = "baseCache", key = "#u.id")
    public User findByUserId(User u) {
        User user = userDao.selectByPrimaryKey(u.getId());
        return user;
    }


}

  • 創(chuàng)建UserProcessController控制器
package com.mico.emptyspring.controller;


import com.mico.emptyspring.entity.User;
import com.mico.emptyspring.service.UserProcessService;
import com.mico.emptyspring.utils.EhcacheUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;


@Controller
@RequestMapping("/user")
public class UserProcessController {

    @Autowired
    private UserProcessService userProcessService;
    @Resource
    private EhCacheCacheManager ehcacheManager;

    @RequestMapping("/index")
    public String index() {
        User user = new User();
        user.setId(1);
        userProcessService.findByUserId(user);
        EhcacheUtils.listAllCache(ehcacheManager);
        return "inner";
    }

    /**
     *
     * @responseBody注解的作用是將controller的方法返回的對(duì)象通過(guò)適當(dāng)?shù)霓D(zhuǎn)換器轉(zhuǎn)換為指定的格式之后奠骄,
     *  寫(xiě)入到response對(duì)象的body區(qū)迁匠,通常用來(lái)返回JSON數(shù)據(jù)或者是XML數(shù)據(jù)剩瓶,需要注意的呢,
     *  在使用此注解之后不會(huì)再走視圖處理器城丧,而是直接將數(shù)據(jù)寫(xiě)入到輸入流中延曙,
     *  他的效果等同于通過(guò)response對(duì)象輸出指定格式的數(shù)據(jù)。@ResponseBody都會(huì)在異步獲取數(shù)據(jù)時(shí)使用,
     *  被其標(biāo)注的處理方法返回的數(shù)據(jù)將輸出到相應(yīng)流中,客戶端獲取并顯示數(shù)據(jù)亡哄。
     * @return
     */
    @ResponseBody
    @RequestMapping("/json")
    public User json() {
        User user = new User();
        user.setId(1);
        User userId = userProcessService.findByUserId(user);
        return userId;
    }
}

  • 如何使用ehcache開(kāi)啟mybatis的二級(jí)緩存枝缔?
    • 要緩存的entity先implements Serializable
    • mybatis注解形式接口,比如@Insert蚊惯,@Selet愿卸,在接口上添加@CacheNamespace注解即可,比如
      package com.mico.emptyspring.dao;
    
      @CacheNamespace
      public interface UserMapper {
         ......
      }
    
    怎么才說(shuō)明hit中了緩存?eg:
    Cache Hit Ratio [com.mico.emptyspring.dao.UserMapper]: 0.5
    • mybatis接口+mapper.xml文件截型,在mapper.xml文件中趴荸,添加配置,官方文檔
    <mapper namespace="org.acme.FooMapper">
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    ...
    </mapper>
    
  • entity中如何設(shè)置主鍵自增?
        @Options(useGeneratedKeys = true,keyProperty = "id")
        @Insert({
                "insert into user (id, username, ",
                "password)",
                "values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, ",
                "#{password,jdbcType=VARCHAR})"
        })
        int insert(User record);
  • 日志中為什么頻繁出現(xiàn)Creating a new SqlSession?
    • Spring與MyBatis整合時(shí)宦焦,MyBatis的一級(jí)緩存在沒(méi)有事務(wù)存在的時(shí)候失效发钝。
    • 在未開(kāi)啟事務(wù)的情況之下,每次查詢赶诊,spring都會(huì)關(guān)閉舊的sqlSession而創(chuàng)建新的sqlSession,因此此時(shí)的一級(jí)緩存是沒(méi)有啟作用的;
    • 在開(kāi)啟事務(wù)的情況之下笼平,spring使用threadLocal獲取當(dāng)前資源綁定同一個(gè)sqlSession园骆,因此此時(shí)一級(jí)緩存是有效的舔痪。
  • 為什么在spring-mvc.xml只掃描控制層,spring-mybatis.xml中排除了控制層锌唾?
    • 只在spring-mybatis.xml中配置<context:component-scan base-package="com.mico.emptyspring"/>
      啟動(dòng)正常锄码,但是任何請(qǐng)求都不會(huì)被攔截夺英,簡(jiǎn)而言之就是@Controller失效

    • 只在spring-mvc.xml中配置上述配置
      啟動(dòng)正常,請(qǐng)求也正常滋捶,但是事物失效痛悯,也就是不能進(jìn)行回滾

    • 在spring-mvc.xml和spring-mybatis.xml中都配置上述信息
      啟動(dòng)正常,請(qǐng)求正常重窟,也是事物失效载萌,不能進(jìn)行回滾

    • 在spring-mybatis.xml中配置如下<context:component-scan base-package="com.mico.emptyspring" />在spring-mvc.xml中配置如下<context:component-scan base-package="com.mico.emptyspring.controller" />此時(shí)啟動(dòng)正常,請(qǐng)求正常巡扇,事物也正常了扭仁。

    • 結(jié)論:org.springframework.web.servlet.DispatcherServletcontextConfigLocation屬性配置的xml中只需要掃描所有帶@Controller注解的類,在其他配置中可以掃描所有其他帶有注解的類(也可以過(guò)濾掉帶@Controller注解的類)厅翔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末乖坠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刀闷,更是在濱河造成了極大的恐慌熊泵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件甸昏,死亡現(xiàn)場(chǎng)離奇詭異顽分,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)施蜜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)怯邪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人花墩,你說(shuō)我怎么就攤上這事悬秉。” “怎么了冰蘑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵和泌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我祠肥,道長(zhǎng)武氓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任仇箱,我火速辦了婚禮县恕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剂桥。我一直安慰自己忠烛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布权逗。 她就那樣靜靜地躺著美尸,像睡著了一般冤议。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上师坎,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天恕酸,我揣著相機(jī)與錄音,去河邊找鬼胯陋。 笑死蕊温,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的遏乔。 我是一名探鬼主播寿弱,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼按灶!你這毒婦竟也來(lái)了症革?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鸯旁,失蹤者是張志新(化名)和其女友劉穎噪矛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體铺罢,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡艇挨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了韭赘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缩滨。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泉瞻,靈堂內(nèi)的尸體忽然破棺而出脉漏,到底是詐尸還是另有隱情,我是刑警寧澤袖牙,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布侧巨,位于F島的核電站,受9級(jí)特大地震影響鞭达,放射性物質(zhì)發(fā)生泄漏司忱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一畴蹭、第九天 我趴在偏房一處隱蔽的房頂上張望坦仍。 院中可真熱鬧,春花似錦叨襟、人聲如沸繁扎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锻离。三九已至,卻和暖如春墓怀,著一層夾襖步出監(jiān)牢的瞬間汽纠,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工傀履, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留虱朵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓钓账,卻偏偏與公主長(zhǎng)得像碴犬,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子梆暮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis 服协? MyBatis 是支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥(niǎo)慢飛閱讀 5,523評(píng)論 0 4
  • 1 Mybatis入門(mén) 1.1 單獨(dú)使用jdbc編程問(wèn)題總結(jié) 1.1.1 jdbc程序 上邊使...
    哇哈哈E閱讀 3,307評(píng)論 0 38
  • MyBatis 理論篇 [TOC] 什么是MyBatis ?MyBatis是支持普通SQL查詢,存儲(chǔ)過(guò)程和高級(jí)映射...
    有_味閱讀 2,902評(píng)論 0 26
  • 斗彩始于明宣德,但實(shí)物罕見(jiàn)唠椭。成化時(shí)期的斗彩最受推崇跳纳,明清文獻(xiàn)中也稱之為成“窯彩”或 "青花間裝五色"。傳世成化斗彩...
    荒唐憶夢(mèng)閱讀 586評(píng)論 0 0
  • 一轉(zhuǎn)眼贪嫂,進(jìn)入幼兒園工作已經(jīng)三個(gè)星期了寺庄,這段時(shí)間里都在忙于應(yīng)對(duì)各種突發(fā)事件,今天要做這個(gè)了明天要交那個(gè)了力崇,這個(gè)必須做...
    零度清爽閱讀 137評(píng)論 0 0