1. 程式人生 > >spring3.x第二章 快速入門

spring3.x第二章 快速入門

第二章 快速入門

2.1 例項功能概述
2.1.1比HelloWorld更適用的例項

  論壇的登陸模組

2.1.2例項功能簡介

  登陸頁面提供輸入賬號密碼的輸入表單。填寫並提交表單,服務端檢查是否匹配,不匹配返回登陸頁面,匹配就成功登陸並重定向到歡迎頁面。

2.2 環境準備

  使用MySQL5.X

2.2.1 建立庫表

  建立使用者表,建立使用者登入表。並插入初始化的一個數據

//新建資料庫
DROP DATABASE IF EXISTS sampledb;
CREATE DATABASE sampledb DEFAULT CHARACTER SET
utf8;
USE sampledb; //新建使用者表 CREATE TABLE t_user( user_id INT AUTO_INCREMENT PRIMARY KEY, user_name VARCHAR(30), credit INT, password VARCHAR(32), last_visit datetime, last_ip VARCHAR(23) )ENGINE=InnoDB; //新建登陸日誌表 CREATE TABLE t_login_log( login_long_id INT AUTO_INCREMENT PRIMARY
KEY, user_id INT, ip VARCHAR(23), login_datetime datetime )ENGINE=InnoDB;
//初始化資料 INSERT INTO t_user(user_name, password)VALUES('admin','123456');
2.2.2 建立工程

  使用MyEclipse

2.2.3 類包及Spring配置檔案規劃

  2.2.3_2017-01-25_11-50-45.png
  Spring可以將所有的配置資訊統一到一個檔案中,也可以放置到多個檔案中。即applicationContext.xml配置檔案。

2.3 持久層
2.3.1 建立領域物件

  領域物件(Domain Object)也稱為實體類。
  使用者領域物件

package com.liwenguang.baobaotao.domain;
import java.util.Date;
public class User implements Serializable{
    private int userId;
    private String userName;
    private String password;
    private int credits;
    //省略Get、Set方法
}
package com.liwenguang.baobaotao.domain;
import java.util.Date;
public class LoginLog implements Serializable{
    private int loginLogId;
    private int userId;
    private String ip;
    private Date loginDate;
    //省略Get、Set方法
}
2.3.2 UserDao和LoginLogDao

  訪問實體類的DAO。

package com.liwenguang.baobaotao.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Repository;
import com.liwenguang.baobaotao.domain.User;
@Repository //通過註解定義一個DAO
public class UserDao {

    /**
     * 根據使用者名稱和密碼獲取匹配的使用者數
     */
    @Autowired //自動注入JdbcTemplate的Bean
    private JdbcTemplate jdbcTemplate;

    public int getMatchCount(String userName, String password){
        String sqlString = "SELECT count(*) FROM t_user"+
                "WHERE user_name = ? and password = ?";
        return jdbcTemplate.queryForInt(sqlString, new Object[]{userName, password});
    }

    /**
     * 根據使用者名稱獲取使用者物件
     * @param userName
     * @return
     */
    public User findUserByUserName(final String userName){
        String sqlString = "SELECT user_id, user_name, credits FROM t_user"
                +" WHERE user_name = ?";
        final User user = new User();
        jdbcTemplate.query(sqlString, new Object[]{userName},
                new RowCallbackHandler() {

                    @Override
                    public void processRow(ResultSet rs) throws SQLException {
                        // 對資料指標進行回撥
                        user.setUserId(rs.getInt("user_id"));
                        user.setUserName(userName);
                        user.setCredits(rs.getInt("credits"));
                    }
                });
        return user;
    }

    /**
     * 更新使用者積分,最後登陸IP,最後登陸時間
     * @param user
     */
    public void updateLoginInfo(User user){
        String sqlString = "UPDATE t_user SET last_visit = ?, last_ip = ?, credits = ?"+
                " WHERE user_id = ?";
        jdbcTemplate.update(sqlString, new Object[]{user.getLastVisit(), user.getLastIp(), user.getCredits()});

    }
}
package com.liwenguang.baobaotao.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.liwenguang.baobaotao.domain.LoginLog;

@Repository
public class LoginLogDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insertLoginLog(LoginLog loginLog){
        String sqlString = "INSERT INTO t_login_log(user_id, ip, login_datetime)"
                +"VALUES(?,?,?)";
        Object[] argsObjects = {loginLog.getUserId(), loginLog.getIp(), loginLog.getLoginDate()};
    }
}
2.3.4 在Spring中裝配DAO

  在以上兩個DAO實現類中都沒有開啟/釋放Connection的程式碼,DAO類究竟如何訪問資料庫呢?所以我們首先宣告一個數據源即資料庫,然後定義一個JdbcTemplate Bean,通過Spring的容器上下文進行Bean的注入。即applicationContext.xml的Spring配置檔案。

<?xml version="1.0" encoding="UTF-8" ?>
<!-- 引用Spring的多個Schema空間的格式定義檔案 -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    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.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <!-- 掃描類包,將標註Spring註解的類自動轉化Bean,同時完成Bean的注入,這樣@Repository以及@Autowires才會起作用  -->
    <context:component-scan base-package="com.liwenguang.baobaotao.dao"/>
    <!-- 定義一個使用DBCP實現的資料來源 -->
    <bean
        id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/sampledb"
        p:username="root"
        p:password=""/>

    <!-- 定義Jdbc模版Bean -->
    <bean
        id="jdbcTemplate"
        class="org.springframework.jdbc.core.JdbcTemplate"
        p:dataSource-ref="dataSource"/>
</beans>
2.4 業務層
2.4.1 UserService
package com.liwenguang.baobaotao.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.liwenguang.baobaotao.dao.LoginLogDao;
import com.liwenguang.baobaotao.dao.UserDao;
import com.liwenguang.baobaotao.domain.LoginLog;
import com.liwenguang.baobaotao.domain.User;
@Service //將UserService標註為一個服務層的Bean
public class UserService {
    @Autowired //注入DAO層的Bean
    private UserDao userDao;
    @Autowired
    private LoginLogDao loginLogDao;
    public boolean hasMatchUser(String userName, String password){
        int matchCount = userDao.getMatchCount(userName, password);
        return matchCount>0;
    }
    public User findUserByUserName(String userName){
        return userDao.findUserByUserName(userName);
    }
    public void loginSuccess(User user){
        user.setCredits(5 + user.getCredits());
        LoginLog loginLog = new LoginLog();
        loginLog.setUserId(user.getUserId());e
        loginLog.setIp(user.getLastIp());
        loginLog.setLoginDate(user.getLastVisit());
        userDao.updateLoginInfo(user);
        loginLogDao.insertLoginLog(loginLog);
    }
}
2.4.2 在Spring中裝配Service
<!-- 配置事務管理器 -->
    <bean
        id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        p:dataSource-ref="dataSource"/>
    <!-- 通過AOP配置提供事務增強,讓service包下所有Bean的所有方法 擁有事務-->
    <aop:config
        proxy-target-class="true">
        <aop:pointcut
            id="serviceMethod"
            expression=" execution(* com.liwenguang.baobaotao.service..*(..))"/>
        <aop:advisor
            pointcut-ref="serviceMethod"
            advice-ref="txAdvice"/>
    </aop:config>
    <tx:advice
        id="txAdvice"
        transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>
2.4.3 單元測試
package com.liwenguang.baobaotao.service;
import static org.junit.Assert.*;
import java.util.Date;
import javax.swing.Spring;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.liwenguang.baobaotao.domain.User;
@RunWith(SpringJUnit4ClassRunner.class) //基於JUnit4的Spring測試框架
@ContextConfiguration(locations={"/applicationContext.xml"}) //啟動Spring容器
public class TestUserService {
    @Autowired //注入Spring容器中的Bean
    private UserService userService;
    @Test
    public void testHasMatchUser() {
        boolean b1 = userService.hasMatchUser("admin", "123456");
        boolean b2 = userService.hasMatchUser("admin", "1111");
        assertTrue(b1);
        assertTrue(!b2);
    }
    @Test
    public void testFindUserByUserName(){
        User user = userService.findUserByUserName("admin");
        assertEquals(user.getUserName(), "admin");
    }
    @Test
    public void testAddLoginLog(){
        User user = userService.findUserByUserName("admin");
        user.setUserId(1);
        user.setUserName("admin");
        user.setLastIp("192.168.12.7");
        user.setLastVisit(new Date());
        userService.loginSuccess(user);
    }
}
2.5 展現層
2.5.1 配置Spring MVC框架

對web.xml檔案進行配置,以便Web容器啟動時能夠自動啟動Spring容器

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <!-- 從類路徑下記載Spring配置檔案,classpath關鍵字特指類路徑下載入 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <!-- 負責啟動Spring容器的監聽器,它將引用上下文引數獲得Spring配置檔案引數 -->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>baobaotao</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>3</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>baobaotao</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
</web-app>
2.5.2 處理登陸請求

  POJO控制器類

package com.liwenguang.baobaotao.web;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.liwenguang.baobaotao.domain.User;
import com.liwenguang.baobaotao.service.UserService;
@Controller //標註為SpringMVC的控制器,處理HTTP的請求,首先會是一個Bean,所以可以使用@Autowired進行Bean的注入
public class LoginController {
    @Autowired
    private UserService userService;
    //負責處理/index.html的請求
    @RequestMapping(value = "/index.html")
    public String loginPage(){
        return "login";
    }
    //負責處理/loginCheck.html的請求
    @RequestMapping(value = "/loginCheck.html")
    public ModelAndView loginCheck(HttpServletRequest request, LoginCommand loginCommand){
        boolean isValidUser = userService.hasMatchUser(loginCommand.getUserName(), loginCommand.getPassword());
        if (!isValidUser) {
            return new ModelAndView("login", "error", "使用者名稱或密碼錯誤。");
        }else{
            User user = userService.findUserByUserName(loginCommand.getUserName());
            user.setLastIp(request.getRemoteAddr());
            user.setLastVisit(new Date());
            userService.loginSuccess(user);
            request.getSession().setAttribute("user", user);
            return new ModelAndView("main");
        }
    }
}
package com.liwenguang.baobaotao.web;
public class LoginCommand {
    private String userName;
    private String password;
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

  Spring MVC配置檔案:編寫完控制器後,需要在baobaotao-servlet中宣告該控制器,掃描Web路徑,指定Spring MVC的仕途解析器。

<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <!-- 掃描web包,應用Spring的註解 -->
    <context:component-scan base-package="com.liwenguang.baobaotao.web"/>
    <!-- 配置檢視解析器,將ModelAndView及字串解析為具體的頁面 -->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:viewClass="org.springframework.web.servlet.view.JstlView" 
        p:prefix="/WEB-INF/jsp/"
        p:suffix=".jsp" />
</beans>
2.5.3 JSP檢視頁面

2.6 執行Web應用

2.7 小結

  複雜的程式碼實現簡單的功能,但是如果新增功能非常方便

2.8 學習中的問題:

  aopalliance-1.0.jar、aspectjweaver-1.7.0.jar、spring-aspects-4.0.2.RELEASE.jar三個包是用於支援applicationContext.xml中宣告的AOP所依賴的三個包。