1. 程式人生 > 實用技巧 >Java後端SSM框架知識點總結

Java後端SSM框架知識點總結

一、配置檔案

1. 兩種註解掃描的區別

1.1 使用MapperScannerConfigurer

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 掃描對映檔案比如:AccountMapper.xml 載入該檔案; 還會掃描介面AccountMapper介面建立代理物件  -->
    <property name="basePackage" value="com.lagou.mapper"/>
</bean>

1.2 使用context:component-scan
標籤

<context:component-scan base-package="com.lagou.service"/>

區別

第一種方法的作用有兩個:第一個是載入com.lagou.mapper包下的xxxMapper.xml檔案;第二個作用是為該包下的介面建立代理物件,存放在IOC容器中;通常是用在dao層,為該層中的介面建立動態代理物件。

第二種方法的作用是對com.lagou.service包下的類建立例項物件放到IOC容器中;通常用在service層,為該層下的實現類建立物件。

2. 各層配置檔案的載入位置

2.1 mybatis配置檔案

在spring配置檔案中建立SqlSessionFactoryBean

例項物件的時候引入mybatis配置檔案。

<bean id="sqlSesionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 注入連線池, public void setDataSource(DataSource dataSource){...}-->
    <property name="dataSource" ref="dataSource"/>
    <!-- 載入mybatis-config.xml
        public void setConfiguration(Configuration configuration) {this.configuration = configuration;}
        因為在SqlSessionFactoryBean類中有configuration的set方法,所以可以使用property來注入
         -->
    <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
</bean>

2.2 spring配置檔案

web.xml配置檔案中建立監聽器的時候載入spring所有的配置檔案(如果spring配置檔案是根據層分別建立的)

<!--監聽器,載入spring所有的配置檔案-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

2.3 載入springMVC配置檔案

web.xml配置檔案中建立前端控制器的時候載入springmvc的配置檔案

<!--前端控制器-->
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc/springmvc.xml</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
</servlet>

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

3. 載入properties配置檔案

3.1 方式一

<properties resource="jdbc.properties"></properties> 

3.2 方式二

<!--需要引入context名稱空間-->
<context:property-placeholder location="classpath:jdbc.properties"/>

4. 載入對映配置檔案

4.1 mybatis核心配置檔案載入對映配置檔案

<mappers>
    <!--:class屬性的方式
            注意:這種方式下xml檔案的位置一定要和介面的位置同包同名
            比如:介面包是com.lagou.mapper,那麼UserMapper.xml的位置也應該是在com.lagou.mapper下
        -->
    <mapper class="com.lagou.mapper.UserMapper"></mapper>
</mappers>

4.2 spring核心配置檔案載入對映配置檔案

<!--Mapper包掃描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 掃描對映檔案比如:AccountMapper.xml 載入該檔案; 還會掃描介面AccountMapper介面建立代理物件  -->
    <property name="basePackage" value="com.lagou.mapper"/>
</bean>

二、SSM

1. mybatis多條件查詢

1.1 重要標籤

resultMap標籤

在實體屬性名與表中屬性名不一致的時候,使用該標籤進行對映。

1.2 多條件查詢

適用於介面方法的引數有多個的情況

方式一

在XXXMapper.xml配置檔案中需要使用到#{arg0}或者#{param1}

<select id="findByIdAndUsername1" resultType="com.lagou.domain.User">
    select * from user where id = #{arg0} and username = #{arg1}
</select>

方式二

使用註解,引入 @Params() 註解獲取引數

//介面中,方法的引數使用@Params()註解
public User findByIdAndName(@Params("id") int id, @(Params"username") String username);
<!--配置檔案中直接使用註解中指定的名字-->
<select id="findByIdAndUsername1" resultType="com.lagou.domain.User">
    select * from user where id = #{id} and username = #{username}
</select>

方式三(推薦)

使用pojo物件的方式,將查詢的結果封裝到實體。因此介面中的方法的引數也是一個實體物件。

public User findByIdAndName(User user);
<select id="findByIdAndUsername3" parameterType="com.lagou.domain.User" resultType="com.lagou.domain.User">
        <!--注意,這裡#{}裡面的值就需要和實體的屬性名保持一致了-->
        select * from user where id = #{id} and username = #{username}
</select>

2. mybatis多表查詢

2.1 聯合查詢

2.1.1 一對一查詢

association標籤、resultZMap標籤 結合使用

<resultMap id="orderMap" type="com.lagou.domain.Order">
<id column="id" property="id"></id>
<result column="ordertime" property="ordertime"></result>
<result column="money" property="money"></result>
	<!--
		一對一(多對一)使用association標籤關聯
property="user" 封裝實體的屬性名
javaType="user" 封裝實體的屬性型別
-->
<association property="user" javaType="com.lagou.domain.User">
<id column="uid" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</association>
</resultMap>
2.1.2 一對多查詢

collection標籤、resultMap標籤結合使用

<resultMap id="userMap" type="com.lagou.domain.User">
    <id column="id" property="id"></id>
    <result column="username" property="username"></result>
    <result column="birthday" property="birthday"></result>
    <result column="sex" property="sex"></result>
    <result column="address" property="address"></result>
    <!--
          一對多使用collection標籤關聯
            property="orderList" 封裝到集合的屬性名
            ofType="order" 封裝集合的泛型型別
        -->
    <collection property="orderList" ofType="com.lagou.domain.Order">
        <id column="oid" property="id"></id>
        <result column="ordertime" property="ordertime"></result>
        <result column="money" property="money"></result>
    </collection>
</resultMap> 
2.1.2 多對多查詢

同一對多查詢差不多,只是在編寫SQL語句的時候,需要關聯一箇中間表。

SELECT * FROM USER u LEFT JOIN user_role ur ON u.`id`=ur.`uid` INNER JOIN role r ON ur.`rid` = r.`id`;
-- user_role就是一箇中間表

2.2 巢狀查詢

只是把聯合查詢語句分成多個部分分步查詢

2.2.1 一對一巢狀查詢

association標籤中要新增select屬性。其他的都和聯合查詢差不多

<!--一對一巢狀查詢-->
<resultMap id="orderMap" type="order">
<id column="id" property="id"></id>
<result column="ordertime" property="ordertime"></result>
<result column="money" property="money"></result>
<!--根據訂單中uid外來鍵,查詢使用者表,即將uid作為引數傳遞到下面的查詢語句-->
<association property="user" javaType="com.lagou.domain.User" column="uid"
   select="com.lagou.mapper.UserMapper.findById">
  </association>
</resultMap>

<select id="findAllWithUser" resultMap="orderMap" >
SELECT * FROM orders
</select>
2.2.2 一對多巢狀查詢
<!--一對多巢狀查詢-->
<resultMap id="userMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!--根據使用者id,查詢訂單表-->
<collection property="orderList" column="id" ofType="com.lagou.domain.Order"
select="com.lagou.mapper.OrderMapper.findByUid"></collection>
</resultMap>

<select id="findAllWithOrder" resultMap="userMap">
SELECT * FROM `user`
</select>
2.2.3 多對多巢狀查詢

和一對多巢狀查詢一樣,只是SQL語句編寫不一致。

<!--多對多巢狀查詢-->
<resultMap id="userAndRoleMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="adress" property="address"></result>
<!--根據使用者id,查詢角色列表-->
<collection property="roleList" column="id" ofType="com.lagou.domain.Role"
select="com.lagou.mapper.RoleMapper.findByUid"></collection>
</resultMap>

<select id="findAllWithRole" resultMap="userAndRoleMap">
    SELECT * FROM `user`
</select> 

3. mybatis開發總結

  • 使用動態代理的方式開發:持久層只編寫介面和Mapper.xml檔案,不編寫實現類。
  • XXXMapper.xml配置檔案的位置必須要和介面所處的位置一致(比如:com.lagou.mapper),配置檔名字也需要同介面的名字保持一致(比如:UserMapper)。
  • mybatis傳統開發方式:在實現類中存在程式碼重複和硬編碼的問題,實際開發中不用。
  • 儘量使用配置檔案的方式開發,不用純註解的方式開發,因為純註解開發要修改原始碼,不好維護。

4. spring兩大核心

4.1 IOC

把物件的建立權利交給spring,降低程式碼的耦合度。

在mybatis開發的測試方法中,需要new SqlSessionFactoryBuilder()。有了spring之後,就可以讓spring來建立該物件。

在之前service層呼叫dao的方法時,需要手動建立 new UserDaoImpl()。有了spring之後,就可以讓spring來建立該物件。

4.2 AOP

在不修改原始碼的情況下,對方法的功能進行增強(轉賬案例)。

5. spring IOC開發

使用註解結合配置檔案開發(推薦)

使用註解開發必須在xml檔案中配置註解掃描

<context:component-scan base-package="com.lagou.service"/>
  • 註解代替bean標籤

    <!--xml方式開發-->
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
    
    // 註解開發
    @Repository // 如果沒有寫value屬性值,Bean的id為:類名首字母小寫
    public class UserDaoImpl implements UserDao {
    }
    
  • 註解代替依賴注入

    <!--xml方式開發-->
    <bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
    <property name="userDao" ref="userDaoImpl"/>
    </bean>
    
    // 註解開發
    @Service
    public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
        
       // 去掉set方法
    
  • 註解方式代替測試類

    // xml方式開發,呼叫spring的API載入xml檔案,並生成物件存放到IOC容器中
    public class AccountServiceTest {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService accountService = (AccountService) classPathXmlApplicationContext.getBean("accountService");
        ...
    }
    
    // 註解結合xml開發的測試類
    @RunWith(SpringJUnit4ClassRunner.class) //@RunWith指定junit的執行環境  SpringJUnit4ClassRunner是spring提供的作為junit執行環境的類
    @ContextConfiguration({"classpath:applicationContext.xml"})
    public class AccountServiceTest {
        ...
    }
    
    // 純註解的測試類
    @RunWith(SpringJUnit4ClassRunner.class) //@RunWith指定junit的執行環境  SpringJUnit4ClassRunner是spring提供的作為junit執行環境的類
    @ContextConfiguration(classes = {SpringConfig.class})
    public class AccountServiceTest {
        ...
    }
    

6. spring AOP開發

使用註解結合配置檔案開發(推薦)

6.1 基於xml方式的AOP開發

  • 建立目標介面和目標實現類(即要給哪個物件增強功能)

    public interface AccountService {
      public void transfer();
    }
    
    public class AccountServiceImpl implements AccountService {
        @Override
        public void transfer() {
            System.out.println("轉賬業務...");
        }
    }
    
  • 建立通知類

    public class MyAdvice {
        public void before() {
            System.out.println("前置通知...");
        }
    }
    
  • 將目標類和通知類物件建立權交給spring

    <!--目標類交給IOC容器-->
    <bean id="accountService" class="com.lagou.service.impl.AccountServiceImpl">
    </bean>
    <!--通知類交給IOC容器-->
    <bean id="myAdvice" class="com.lagou.advice.MyAdvice"></bean>
    
  • 在核心配置檔案中配置織入關係,及切面

    <aop:config>
    <!--引入通知類-->
    <aop:aspect ref="myAdvice">
    <!--配置目標類的transfer方法執行時,使用通知類的before方法進行前置增強-->
    <aop:before method="before"
    pointcut="execution(public void
    com.lagou.service.impl.AccountServiceImpl.transfer())">
          </aop:before>
    </aop:aspect>
    </aop:config>
    

    其中,execution(public void com.lagou.service.impl.AccountServiceImpl.transfer())是切面表示式。

    可以將切面表示式單獨抽取出來,方便使用

    <aop:config>
    <!--抽取的切點表示式-->
      <aop:pointcut id="myPointcut" expression="execution(* com.lagou.service..*.*
    (..))"> </aop:pointcut>
    <aop:aspect ref="myAdvice">
    <aop:before method="before" pointcut-ref="myPointcut"></aop:before>
    </aop:aspect>
    </aop:config>
    

6.2 基於註解的AOP開發

  • 建立目標介面和實現類

    public interface AccountService {
        public void transfer();
    }
    
    public class AccountServiceImpl implements AccountService {
        @Override
        public void transfer() {
            System.out.println("轉賬業務...");
        }
    }
    
  • 建立通知類

    public class MyAdvice {
        public void before() {
            System.out.println("前置通知...");
        }
    }
    
  • 將目標類和通知類物件建立權交給spring

    @Service
    public class AccountServiceImpl implements AccountService {}
    @Component
    public class MyAdvice {}
    
  • 在通知類中使用註解配置織入關係,升級為切面類

    @Component
    @Aspect
    public class MyAdvice {
        @Before("execution(* com.lagou..*.*(..))")
        public void before() {
            System.out.println("前置通知...");
        }
    }
    

    這裡也可以抽取切面表示式

    @Component
    @Aspect
    public class MyAdvice {
        @Pointcut("execution(* com.lagou..*.*(..))")
        public void myPoint(){}
        @Before("MyAdvice.myPoint()")
        public void before() {
            System.out.println("前置通知...");
    }
    
  • 在配置檔案中開啟元件掃描和 AOP 的自動代理

    <!--元件掃描-->
    <context:component-scan base-package="com.lagou"/>
    <!--aop的自動代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    

6.3 對比xml開發和註解開發

  • 註解方式:在介面實現類新增@Service註解;在通知類上新增@Component@Aspect註解,織入關係就在通知類裡面編寫。
  • XML方式:物件建立是在spring配置檔案中編寫,織入關係也是在配置檔案中編寫。

6.4 spring中的事務控制

宣告式事務控制(開發中常用)

6.4.1 基於XML的宣告式事務控制

解決什麼問題呢?在執行一個業務的時候(比如轉賬操作),如果全部執行成功就提交事務,如果出現異常就回滾事務。這中間就可以通過配置事務管理器來實現

主要配置如下:

事務管理器通知配置

<!--事務管理器-->
<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="*"/>
</tx:attributes>
</tx:advice>

事務管理器AOP配置

<!--aop配置-->
<aop:config>
<!--切面配置-->
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* com.lagou.serivce..*.*(..))">
</aop:advisor>
</aop:config>

總結:

相比較於之前基於xml方式的AOP開發,我們需要編寫一個通知類,然後在該類中編寫前置通知、後置通知、異常通知、最終通知的業務邏輯,然後再配置檔案中指定通知。

現在通過事務管理器,我們只需要在配置檔案中新增一個事務管理器物件的bean標籤,然後在tx:advice標籤中引入該事務管理器物件,最後在切面配置中配置該通知就可以了。不需要再去建立一個通知類,然後寫各種通知的處理邏輯。

事務管理器AOP配置使用的是aop:advisor標籤,而基於xml方式的AOP配置使用的是aop:aspect標籤。

6.4.2 基於註解的宣告式事務控制

直接在service層的實現類中需要事務控制的方法上增加@Transactional註解,或者直接在類上新增@Transactional註解

@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    
    @Transactional(propagation = Propagation.REQUIRED, isolation =
                   Isolation.REPEATABLE_READ, timeout = -1, readOnly = false)
    @Override
    public void transfer(String outUser, String inUser, Double money) {
        accountDao.out(outUser, money);
        int i = 1 / 0;
        accountDao.in(inUser, money);
    }
}

然後在配置檔案中配置如下:

<!--事務管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>

<!--事務的註解支援-->
<tx:annotation-driven/>

其他的就都不用配置了

7. springMVC開發

7.1 springMVC三大元件

  • 處理器對映器:找到Controller類中的需要執行的方法,返回給前端控制器。

    @Controller
    @RequestMapping("/user")
    @Transactional
    public class UserController {
    
        @Autowired
        private IUserService userService;
    
        @RequestMapping(value = "/login.do" , method = RequestMethod.POST)
        @ResponseBody
        public ServiceResponse<User> login(String username, String password, HttpSession session) {
            ServiceResponse<User> response = userService.login(username, password);
            // 判斷是否登入成功
            if (response.getStatus() == ResponseCode.SUCCESS.getCode()) {
                session.setAttribute(Const.CURRENT_USER, response.getData());
            }
            return response;
        }
        
    // 比如使用者通過瀏覽器訪問www.lagou.com/user/login.do,那麼先經過前端控制器,然後前端控制器將請求傳送給處理器對映器,處理器對映器就到controller層去找‘/user/login.do’資源路徑,看看能匹配到哪個類中的哪個方法。
    // 最後找到UserController類中的login方法
    // 上面的處理器對映器是通過xml的方式進行指定的,如果是通過註解或者介面的方式進行指定,那麼springMVC都可以實現不同的對映方式。
    
  • 處理器介面卡:能夠對多個Controller類進行適配

  • 檢視解析器

7.2 配置檔案

web.xml

  • 配置前端控制器

    <!--前端控制器,載入springmvc核心配置檔案-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc/springmvc.xml</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    
  • 配置監聽器

    <!--監聽器,載入spring所有的配置檔案-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/applicationContext-*.xml</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
  • 中文亂碼過濾器

    <!--配置全域性過濾的filter-->
    <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-
    class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    spring-mvc.xml

  • 配置處理器對映器和處理器介面卡

    <!--處理器對映器和介面卡增強-->
    <mvc:annotation-driven></mvc:annotation-driven>
    
  • 配置檢視解析器

    <!--檢視解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    
  • 開啟靜態資源

    <!--在springmvc配置檔案中開啟DefaultServlet處理靜態資源-->
    <mvc:default-servlet-handler/>
    
  • 配置自定義型別轉換器

    SpringMVC 預設已經提供了一些常用的型別轉換器;例如:客戶端提交的字串轉換成int型進行參
    數設定,日期格式型別要求為:yyyy/MM/dd 不然的話會報錯,對於特有的行為,SpringMVC提供了自
    定義型別轉換器方便開發者自定義處理。

    <!--自定義轉換器配置-->
    <bean id="conversionService"
    class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
    <set>
    <bean class="com.lagou.converter.DateConverter"></bean>
    </set>
    </property>
    </bean>
    
    public class DateConverter implements Converter<String, Date> {
        public Date convert(String dateStr) {
            //將日期字串轉換成日期物件 返回
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            Date date = null;
            try {
                date = format.parse(dateStr);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }
    
  • 配置自定義異常處理器

    public class GlobalExceptionResolver implements HandlerExceptionResolver {
        @Override
        public ModelAndView resolveException(HttpServletRequest request,
                                             HttpServletResponse response, Object handler, Exception ex) {
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("error", ex.getMessage());
            modelAndView.setViewName("error");
            return modelAndView;
        }
    }
    
    <bean id="globalExecptionResovler"
    class="com.lagou.exception.GlobalExecptionResovler"></bean>
    
  • 掃描路徑

    <context:component-scan base-package="com.lagou.controller"></context:component-scan>
    

8. 方法引數名與請求引數名不一致

8.1 dao層介面方法的引數名與請求的引數名不一致

使用的是@Params() 註解

//介面中,方法的引數使用@Params()註解
public User findByIdAndName(@Params("id") int id, @(Params"username") String username);

8.2 controller層業務方法的引數名與請求的引數不一致

使用@RequestParam註解

<!--請求時傳遞的引數名-->
<a href="${pageContext.request.contextPath}/user/findByPage?pageNo=2">
分頁查詢
</a>
@RequestMapping("/findByPage")
public String findByPage(@RequestParam(name = "pageNo", defaultValue = "1")
Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize) {
System.out.println(pageNum);
System.out.println(pageSize);
return "success";
}

9. ajax非同步互動

9.1 @RequestBody註解

該註解用於Controller的方法的形參宣告,當使用ajax提交併指定contentType為json形式時,通過
HttpMessageConverter介面轉換為對應的POJO物件。

<button id="btn1">ajax非同步提交</button>
<script>
$("#btn1").click(function () {
let url = '${pageContext.request.contextPath}/ajaxRequest';
let data = '[{"id":1,"username":"張三"},{"id":2,"username":"李四"}]';
$.ajax({
type: 'POST',
url: url,
data: data,
contentType: 'application/json;charset=utf-8',
success: function (resp) {
    	alert(JSON.stringify(resp))
}
})
})
</script>
@RequestMapping(value = "/ajaxRequest")
public void ajaxRequest(@RequestBody List<User>list) {
System.out.println(list);
}

9.2 @ResponseBody註解

該註解用於將Controller的方法返回的物件,通過HttpMessageConverter介面轉換為指定格式的數
據如:json,xml等,通過Response響應給客戶端。

// 預設返回的資料是json格式
@RequestMapping(value = "/ajaxRequest")
@ResponseBody
public List<User> ajaxRequest(@RequestBody List<User> list) {
System.out.println(list);
return list;
}

10 springMVC中的過濾器、攔截器和前端控制器

10.1 三者的執行順序

過濾器-->攔截器-->前端控制器

10.2 三者的功能

springMVC的攔截器,只能攔截位址列訪問對controller的請求,無論你攔截的地址配置到天上,它只攔截對controller的請求。

springMVC的過濾器,這個會根據你配置的路徑選擇性攔截,攔截什麼請求路徑,按個人口味選擇;

springMVC的前端控制器,這個也是根據你配置的路徑選擇性攔截,若直接配置根路徑,靜態資源也會被攔截;

10.3 攔截器和過濾器的區別

過濾器是Servlet中的一部分,任何Javaweb工程都可以使用;而攔截器是springmvc自己的,只有使用了springmvc框架才可以使用攔截器。

過濾器可以對所有要訪問的資源進行攔截;而攔截器只能攔截控制器類中的方法,如果訪問js、html、css、jsp、image是不會攔截的。

三、SSM整合開發

1. spring整合mybatis

將物件的建立權交給spring,原本使用單獨的mybatis開發時,在測試類中會手動建立介面的代理類物件,程式碼如下:

public class MybatisTest {
    @Test
    public void testFindAll() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        AccountDao mapper = sqlSession.getMapper(AccountDao.class);
        List<Account> accountList = mapper.findAll();
        for (Account account : accountList) {
            System.out.println(account);
        }
    }
}

通過spring整合mybatis之後,就不要手動去建立了,只需要在spring的核心配置檔案中進行配置就可以了,程式碼如下:

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="druidDataSource"></property>
    <!--spring配置檔案中起別名的方法-->
    <property name="typeAliasesPackage" value="com.lagou.domain"></property>
</bean>

<!--將AccountDAO介面的實現類物件交給spring建立,需要使用以下類對介面進行掃描,建立介面實現類-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.lagou.dao"></property>
</bean>

值得一提的是:在sqlSessionFactory標籤中,可以配置很多的屬性。比如:

<!--載入mybatis核心配置檔案-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>

在spring的核心配置檔案中配置以上配置之後,原本在mybatis中的以下配置就可以刪除了

<!--配置別名-->
<typeAliases>
    <typeAlias type="com.lagou.domain.Account" alias="account"></typeAlias>
</typeAliases>

<!--environments:執行環境-->
<environments default="development">
    <!--可以配置多個環境-->
    <environment id="development">
        <!--當前的事務管理器是JDBC-->
        <transactionManager type="JDBC"></transactionManager>
        <!--資料來源資訊
            POOLED:使用mybatis的連線池
            UNPOOLED:不使用連線池
            -->
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
</environments>

<!--引入對映配置檔案,動態代理的時候用到-->
<mappers>
    <mapper class="com.lagou.dao.AccountDao"></mapper>
</mappers>

spring整合mybatis之後,測試的時候只需要將dao層的介面注入到service層就可以了,不需要再手動建立,程式碼如下:

public class AccountServiceImpl implements AccountService {
    // 注入介面
    @Autowired
    private AccountDao accountDao;
    @Override
    public List<Account> findAll() {
        List<Account> accountList = accountDao.findAll();
        return accountList;
    }

    @Override
    public void save(Account account) {
        accountDao.save(account);
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {

    @Autowired
    private AccountService accountService;
    @Test
    public void testFindAll() {
        accountService.findAll();
    }
}

2. spring整合springmvc

整合的地方就是讓springmvc載入spring的配置檔案,在web.xml檔案中整合如下:

<!--web.xml-->
<!--監聽器,其作用是監聽ServletContext容器,一旦啟動就載入spring的核心配置檔案-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

四、springboot開發

1. 全域性配置檔案

Spring Boot使用一個application.properties或者application.yaml的檔案作為全域性配置檔案,該檔案存放在src/main/resource目錄或者類路徑的/config

1.1 application.properties配置檔案

可以配置系統屬性、環境變數、命令引數等資訊,也可以是自定義配置檔名稱和位置。

# tomcat服務埠
server.port=8081
# spring相關配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.config.additional-location=
spring.config.location=
spring.config.name=application
# person實體類相關配置
person.id=1
person.name=tom
person.hobby=吃飯,睡覺,打遊戲
person.family=father,mother
person.map.k1=v1
person.map.k2=v2
person.pet.type=dog
person.pet.name=旺財

1.2 application.yaml配置檔案

YAML檔案格式是Spring Boot支援的一種JSON超集檔案格式,相較於傳統的Properties配置檔案,YAML檔案以資料為核心,是一種更為直觀且容易被電腦識別的資料序列化格式。

注意:冒號後面必須要有一個空格

  • value值為普通資料型別(例如數字、字串、布林等)

    server:
        port: 8080
        servlet:
        	context-path: /hello
    
  • value值為陣列和單列集合

    person:
    	hobby: [play,read,sleep]
    
  • value值為Map集合和物件

    person:
        map: {k1: v1,k2: v2}
    

1.3 注意事項

使用application.yaml配置檔案進行測試時需要提前將application.properties配置檔案中編寫的配置註釋,這是因為application.properties配置檔案會覆蓋application.yaml配置檔案。

2. 配置檔案屬性值的注入

使用Spring Boot全域性配置檔案設定屬性時:

如果配置屬性是Spring Boot已有屬性,例如服務埠server.port,那麼Spring Boot內部會自動掃描並讀取這些配置檔案中的屬性值並覆蓋預設屬性。

如果配置的屬性是使用者自定義屬性,例如剛剛自定義的Person實體類屬性,還必須在程式中注入這些配置屬性方可生效。

Spring Boot支援多種注入配置檔案屬性的方式,下面來介紹如何使用註解@ConfigurationProperties和@Value注入屬性

2.1 使用@ConfigurationProperties注入屬性

@Component
@ConfigurationProperties(prefix = "person")
public class Person {
      private int id; 
      // 屬性的setXX()方法
      public void setId(int id) {
        this.id = id;
     }
}

上述程式碼使用@Component和@ConfigurationProperties(prefix = “person”)將配置檔案中的每個屬性對映到person類元件中。

2.2 使用@Value注入屬性

@Value註解是Spring框架提供的,用來讀取配置檔案中的屬性值並逐個注入到Bean物件的對應屬性中,Spring Boot框架從Spring框架中對@Value註解進行了預設繼承,所以在Spring Boot框架中還可以使用該註解讀取和注入配置檔案屬性值。使用@Value注入屬性的示例程式碼如下:

@Component
public class Person {
    @Value("${person.id}")
      private int id; 
}

上述程式碼中,使用@Component和@Value注入Person實體類的id屬性。其中,@Value不僅可以將配置檔案的屬性注入Person的id屬性,還可以直接給id屬性賦值,這點是@ConfigurationProperties不支援的.

@Component
public class Student {
       @Value("${person.id}")
      private int id;
      @Value("${person.name}")
       private String name; //名稱

       //省略toString
}

Student類使用@Value註解將配置檔案的屬性值讀取和注入。
從上述示例程式碼可以看出,使用@Value註解方式需要對每一個屬性注入設定,同時又免去了屬性的setXX()方法.

3. 自定義配置檔案

3.1 使用@PropertySource載入配置檔案

  • 開啟Spring Boot專案的resources目錄,在專案的類路徑下新建一個test.properties自定義配置檔案,在該配置檔案中編寫需要設定的配置屬性

    #對實體類物件MyProperties進行屬性配置
    test.id=110
    test.name=test
    
  • 在com.lagou.pojo包下新建立一個配置類MyProperties,提供test.properties自定義配置檔案中對應的屬性,並根據@PropertySource註解的使用進行相關配置

    @Component // 自定義配置類
    @PropertySource("classpath:test.properties") // 指定自定義配置檔案位置和名稱
    @ConfigurationProperties(prefix = "test") // 指定配置檔案注入屬性字首
    public class MyProperties {
          private int id;
          private String name;
          // 省略屬性getXX()和setXX()方法
          // 省略toString()方法
    }
    

說明:

@PropertySource("classpath:test.properties")註解指定了自定義配置檔案的位置和名稱,此示例表示自定義配置檔案為classpath類路徑下的test.properties檔案;

@ConfigurationProperties(prefix = "test")註解將上述自定義配置檔案test.properties中以test開頭的屬性值注入到該配置類屬性中。

3.2 使用@Configuration編寫自定義配置類

// 實體類
public class MyService {
}
@Configuration // 定義該類是一個配置類````
public class MyConfig {
      @Bean // 將返回值物件作為元件新增到Spring容器中,該元件id預設為方法名
      public MyService myService(){
        return new MyService();
     }
}

MyConfig是@Configuration註解宣告的配置類(類似於聲明瞭一個XML配置檔案),該配置類會被Spring Boot自動掃描識別;使用@Bean註解的myService()方法,其返回值物件會作為元件新增到了Spring容器中(類似於XML配置檔案中的標籤配置),並且該元件的id預設是方法名myService.

4. SpringBoot整合MyBatis

4.1 編寫與資料表對應的實體類

public class Comment {
    private Integer id;
    private String content;
    private String author;
    private Integer aId;
    // 省略屬性getXX()和setXX()方法
    // 省略toString()方法
}
public class Article {
    private Integer id;
    private String title;
    private String content;
    // 省略屬性getXX()和setXX()方法
    // 省略toString()方法
}

4.2 在application.properties配置檔案中進行資料庫連線配置

# MySQL資料庫連線配置
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

4.3 註解方式整合Mybatis

  • 建立一個對t_comment表資料操作的介面CommentMapper

    @Mapper
    public interface CommentMapper {
        @Select("SELECT * FROM t_comment WHERE id =#{id}")
        public Comment findById(Integer id);
    }
    

    需要在類上新增@Mapper註解, 然後在方法上新增@Select註解

4.4 使用配置檔案的方式整合mybatis

  • 建立一個用於對資料庫表t_article資料操作的介面ArticleMapper

    @Mapper
    public interface ArticleMapper {
        public Article selectArticle(Integer id);
    }
    
  • 建立XML對映檔案

    resources目錄下建立一個統一管理對映檔案的包mapper,並在該包下編寫與ArticleMapper介面對應的對映檔案ArticleMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.lagou.mapper.ArticleMapper">
    <select id="selectArticle" resultType="Article">
    select * from Article
    </select>
    </mapper>
    
  • 在application.properties配置檔案中做如下配置

    #開啟駝峰命名匹配對映
    mybatis.configuration.map-underscore-to-camel-case=true
    
    #配置MyBatis的xml配置檔案路徑
    mybatis.mapper-locations=classpath:mapper/*.xml
    

5. SpringBoot整合SSM

最核心的地方是要在application.yml配置檔案中配置spring和mybatis的相關配置,其他的基本都一樣的。

#伺服器配置
server:
port: 8090
servlet:
  context-path: /
# spring相關配置
spring:
   datasource:
       name: druid
       type: com.alibaba.druid.pool.DruidDataSource
       url: jdbc:mysql://localhost:3306/spring_db?characterEncoding=utf-
       8&serverTimezone=UTC
       username: root
       password: root
       driver-class-name: com.mysql.jdbc.Driver
   mvc:
       view:
       prefix: /
       suffix: .html
       
# mybatis相關配置
mybatis:
    mapper-locations: classpath:mapper/*Mapper.xml #宣告Mybatis對映檔案所在的位置